Compare commits
102 Commits
17.0.0
...
runtime_in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10e482ee5c | ||
|
|
c8734b3e1d | ||
|
|
8447d36206 | ||
|
|
969067242b | ||
|
|
32859cdf3c | ||
|
|
30210a2c02 | ||
|
|
d871af007a | ||
|
|
29577dab24 | ||
|
|
000f788b65 | ||
|
|
ca17caf6c4 | ||
|
|
e7e9a298c0 | ||
|
|
8571b28664 | ||
|
|
7e0d063154 | ||
|
|
113dc01dc7 | ||
|
|
aac28e7b9f | ||
|
|
24e533eba7 | ||
|
|
ca1fe2b41b | ||
|
|
57900a9f44 | ||
|
|
363861f70c | ||
|
|
9555859691 | ||
|
|
78a568d14a | ||
|
|
9ff28439d1 | ||
|
|
bfcc29e64b | ||
|
|
927b9de2a5 | ||
|
|
5af57f8010 | ||
|
|
0ce81c4fed | ||
|
|
a2484be7c3 | ||
|
|
833efe0e2d | ||
|
|
554ad022a6 | ||
|
|
a3e5d0a91a | ||
|
|
b8fd304546 | ||
|
|
71a06985af | ||
|
|
73d555b402 | ||
|
|
a5368e6fe4 | ||
|
|
20e9cd17f6 | ||
|
|
cb08c79a0a | ||
|
|
bff59925de | ||
|
|
1a796b5515 | ||
|
|
cbd48c0eb4 | ||
|
|
18dd05fba5 | ||
|
|
232262c02a | ||
|
|
6c4afb3a70 | ||
|
|
b6a803f48c | ||
|
|
dbe555a3c3 | ||
|
|
1a9b117d53 | ||
|
|
11778f5048 | ||
|
|
399f4df739 | ||
|
|
e7890b7c62 | ||
|
|
b589b490c3 | ||
|
|
72c05ecee0 | ||
|
|
968ce0a03f | ||
|
|
3062dec77e | ||
|
|
9ea55ba620 | ||
|
|
f57f4077fd | ||
|
|
006d1fa1df | ||
|
|
b1e834a8df | ||
|
|
28e4b1bd73 | ||
|
|
35a5d6a66c | ||
|
|
01b19247f1 | ||
|
|
15ea024d48 | ||
|
|
ce5a2614fa | ||
|
|
beda0966db | ||
|
|
1fd5a96561 | ||
|
|
be8c5d01c6 | ||
|
|
97c5c11c25 | ||
|
|
7d660acc05 | ||
|
|
ab71df3ce1 | ||
|
|
37adc03c11 | ||
|
|
3db2ece145 | ||
|
|
1bbb03302a | ||
|
|
c63f9eae0f | ||
|
|
a73e0bd23b | ||
|
|
c5491a4e58 | ||
|
|
3fb012e2e9 | ||
|
|
9c1c9896a3 | ||
|
|
c091fe1a45 | ||
|
|
a20a295a3b | ||
|
|
86335dd4ac | ||
|
|
432bf21f02 | ||
|
|
1ac37b692c | ||
|
|
338eed0c06 | ||
|
|
66b19448b0 | ||
|
|
a00ef22d6d | ||
|
|
e5d20474da | ||
|
|
91bc312190 | ||
|
|
82f1fbff0b | ||
|
|
7c6785176a | ||
|
|
586932ebf8 | ||
|
|
edbfe1404b | ||
|
|
6f22443513 | ||
|
|
e5d13a2478 | ||
|
|
d119157948 | ||
|
|
85c0af4fa0 | ||
|
|
2d32d03ba3 | ||
|
|
28890bf126 | ||
|
|
b9b1468d15 | ||
|
|
3aca271ef5 | ||
|
|
dec766228d | ||
|
|
95837d34f1 | ||
|
|
145933b037 | ||
|
|
6a8c61c026 | ||
|
|
978439191f |
2
CODEOWNERS
Normal file
2
CODEOWNERS
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# This file was generated by https://github.com/audrow/update-ros2-repos
|
||||||
|
* @ivanpauno @hidmic @wjwwood
|
||||||
@@ -8,7 +8,8 @@ rclcpp provides the standard C++ API for interacting with ROS 2.
|
|||||||
|
|
||||||
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
|
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
|
||||||
|
|
||||||
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components.
|
The link to the latest API documentation can be found on the rclcpp package info page, at the [ROS Index](https://index.ros.org/p/rclcpp/).
|
||||||
|
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,67 @@
|
|||||||
Changelog for package rclcpp
|
Changelog for package rclcpp
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
19.3.0 (2023-03-01)
|
||||||
|
-------------------
|
||||||
|
* Fix memory leak in tracetools::get_symbol() (`#2104 <https://github.com/ros2/rclcpp/issues/2104>`_)
|
||||||
|
* Service introspection (`#1985 <https://github.com/ros2/rclcpp/issues/1985>`_)
|
||||||
|
* Allow publishing borrowed messages with intra-process enabled (`#2108 <https://github.com/ros2/rclcpp/issues/2108>`_)
|
||||||
|
* to fix flaky test about TestTimeSource.callbacks (`#2111 <https://github.com/ros2/rclcpp/issues/2111>`_)
|
||||||
|
* Contributors: Brian, Chen Lihui, Christophe Bedard, Miguel Company
|
||||||
|
|
||||||
|
19.2.0 (2023-02-24)
|
||||||
|
-------------------
|
||||||
|
* to create a sublogger while getting child of Logger (`#1717 <https://github.com/ros2/rclcpp/issues/1717>`_)
|
||||||
|
* Fix documentation of Context class (`#2107 <https://github.com/ros2/rclcpp/issues/2107>`_)
|
||||||
|
* fixes for rmw callbacks in qos_event class (`#2102 <https://github.com/ros2/rclcpp/issues/2102>`_)
|
||||||
|
* Contributors: Alberto Soragna, Chen Lihui, Silvio Traversaro
|
||||||
|
|
||||||
|
19.1.0 (2023-02-14)
|
||||||
|
-------------------
|
||||||
|
* Add support for timers on reset callback (`#1979 <https://github.com/ros2/rclcpp/issues/1979>`_)
|
||||||
|
* Topic node guard condition in executor (`#2074 <https://github.com/ros2/rclcpp/issues/2074>`_)
|
||||||
|
* Fix bug on the disorder of calling shutdown callback (`#2097 <https://github.com/ros2/rclcpp/issues/2097>`_)
|
||||||
|
* Contributors: Barry Xu, Chen Lihui, mauropasse
|
||||||
|
|
||||||
|
19.0.0 (2023-01-30)
|
||||||
|
-------------------
|
||||||
|
* Add default constructor to NodeInterfaces (`#2094 <https://github.com/ros2/rclcpp/issues/2094>`_)
|
||||||
|
* Fix clock state cached time to be a copy, not a reference. (`#2092 <https://github.com/ros2/rclcpp/issues/2092>`_)
|
||||||
|
* Fix -Wmaybe-uninitialized warning (`#2081 <https://github.com/ros2/rclcpp/issues/2081>`_)
|
||||||
|
* Fix the keep_last warning when using system defaults. (`#2082 <https://github.com/ros2/rclcpp/issues/2082>`_)
|
||||||
|
* Add in a fix for older compilers. (`#2075 <https://github.com/ros2/rclcpp/issues/2075>`_)
|
||||||
|
* Contributors: Alexander Hans, Chris Lalancette, Shane Loretz
|
||||||
|
|
||||||
|
18.0.0 (2022-12-29)
|
||||||
|
-------------------
|
||||||
|
* Implement Unified Node Interface (NodeInterfaces class) (`#2041 <https://github.com/ros2/rclcpp/issues/2041>`_)
|
||||||
|
* Do not throw exception if trying to dequeue an empty intra-process buffer (`#2061 <https://github.com/ros2/rclcpp/issues/2061>`_)
|
||||||
|
* Move event callback binding to PublisherBase and SubscriptionBase (`#2066 <https://github.com/ros2/rclcpp/issues/2066>`_)
|
||||||
|
* Implement validity checks for rclcpp::Clock (`#2040 <https://github.com/ros2/rclcpp/issues/2040>`_)
|
||||||
|
* Explicitly set callback type (`#2059 <https://github.com/ros2/rclcpp/issues/2059>`_)
|
||||||
|
* Fix logging macros to build with msvc and cpp20 (`#2063 <https://github.com/ros2/rclcpp/issues/2063>`_)
|
||||||
|
* Add clock type to node_options (`#1982 <https://github.com/ros2/rclcpp/issues/1982>`_)
|
||||||
|
* Fix nullptr dereference in prune_requests_older_than (`#2008 <https://github.com/ros2/rclcpp/issues/2008>`_)
|
||||||
|
* Remove templating on to_rcl_subscription_options (`#2056 <https://github.com/ros2/rclcpp/issues/2056>`_)
|
||||||
|
* Fix SharedFuture from async_send_request never becoming valid (`#2044 <https://github.com/ros2/rclcpp/issues/2044>`_)
|
||||||
|
* Add in a warning for a KeepLast depth of 0. (`#2048 <https://github.com/ros2/rclcpp/issues/2048>`_)
|
||||||
|
* Mark rclcpp::Clock::now() as const (`#2050 <https://github.com/ros2/rclcpp/issues/2050>`_)
|
||||||
|
* Fix a case that did not throw ParameterUninitializedException (`#2036 <https://github.com/ros2/rclcpp/issues/2036>`_)
|
||||||
|
* Update maintainers (`#2043 <https://github.com/ros2/rclcpp/issues/2043>`_)
|
||||||
|
* Contributors: Alberto Soragna, Audrow Nash, Chen Lihui, Chris Lalancette, Jeffery Hsu, Lei Liu, Mateusz Szczygielski, Shane Loretz, andrei, mauropasse, methylDragon
|
||||||
|
|
||||||
|
17.1.0 (2022-11-02)
|
||||||
|
-------------------
|
||||||
|
* MultiThreadExecutor number of threads is at least 2+ in default. (`#2032 <https://github.com/ros2/rclcpp/issues/2032>`_)
|
||||||
|
* Fix bug that a callback not reached (`#1640 <https://github.com/ros2/rclcpp/issues/1640>`_)
|
||||||
|
* Set the minimum number of threads of the Multithreaded executor to 2 (`#2030 <https://github.com/ros2/rclcpp/issues/2030>`_)
|
||||||
|
* check thread whether joinable before join (`#2019 <https://github.com/ros2/rclcpp/issues/2019>`_)
|
||||||
|
* Set cpplint test timeout to 3 minutes (`#2022 <https://github.com/ros2/rclcpp/issues/2022>`_)
|
||||||
|
* Make sure to include-what-you-use in the node_interfaces. (`#2018 <https://github.com/ros2/rclcpp/issues/2018>`_)
|
||||||
|
* Do not clear entities callbacks on destruction (`#2002 <https://github.com/ros2/rclcpp/issues/2002>`_)
|
||||||
|
* fix mismatched issue if using zero_allocate (`#1995 <https://github.com/ros2/rclcpp/issues/1995>`_)
|
||||||
|
* Contributors: Alexis Paques, Chen Lihui, Chris Lalancette, Cristóbal Arroyo, Tomoya Fujita, mauropasse, uupks
|
||||||
|
|
||||||
17.0.0 (2022-09-13)
|
17.0.0 (2022-09-13)
|
||||||
-------------------
|
-------------------
|
||||||
* Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS (`#1978 <https://github.com/ros2/rclcpp/issues/1978>`_)
|
* Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS (`#1978 <https://github.com/ros2/rclcpp/issues/1978>`_)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ find_package(tracetools REQUIRED)
|
|||||||
# Default to C++17
|
# Default to C++17
|
||||||
if(NOT CMAKE_CXX_STANDARD)
|
if(NOT CMAKE_CXX_STANDARD)
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
endif()
|
endif()
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
# About -Wno-sign-conversion: With Clang, -Wconversion implies -Wsign-conversion. There are a number of
|
# About -Wno-sign-conversion: With Clang, -Wconversion implies -Wsign-conversion. There are a number of
|
||||||
@@ -48,6 +49,11 @@ set(${PROJECT_NAME}_SRCS
|
|||||||
src/rclcpp/detail/rmw_implementation_specific_subscription_payload.cpp
|
src/rclcpp/detail/rmw_implementation_specific_subscription_payload.cpp
|
||||||
src/rclcpp/detail/utilities.cpp
|
src/rclcpp/detail/utilities.cpp
|
||||||
src/rclcpp/duration.cpp
|
src/rclcpp/duration.cpp
|
||||||
|
src/rclcpp/dynamic_typesupport/dynamic_message.cpp
|
||||||
|
src/rclcpp/dynamic_typesupport/dynamic_message_type.cpp
|
||||||
|
src/rclcpp/dynamic_typesupport/dynamic_message_type_builder.cpp
|
||||||
|
src/rclcpp/dynamic_typesupport/dynamic_message_type_support.cpp
|
||||||
|
src/rclcpp/dynamic_typesupport/dynamic_serialization_support.cpp
|
||||||
src/rclcpp/event.cpp
|
src/rclcpp/event.cpp
|
||||||
src/rclcpp/exceptions/exceptions.cpp
|
src/rclcpp/exceptions/exceptions.cpp
|
||||||
src/rclcpp/executable_list.cpp
|
src/rclcpp/executable_list.cpp
|
||||||
@@ -92,8 +98,9 @@ set(${PROJECT_NAME}_SRCS
|
|||||||
src/rclcpp/parameter_value.cpp
|
src/rclcpp/parameter_value.cpp
|
||||||
src/rclcpp/publisher_base.cpp
|
src/rclcpp/publisher_base.cpp
|
||||||
src/rclcpp/qos.cpp
|
src/rclcpp/qos.cpp
|
||||||
src/rclcpp/qos_event.cpp
|
src/rclcpp/event_handler.cpp
|
||||||
src/rclcpp/qos_overriding_options.cpp
|
src/rclcpp/qos_overriding_options.cpp
|
||||||
|
src/rclcpp/dynamic_subscription.cpp
|
||||||
src/rclcpp/serialization.cpp
|
src/rclcpp/serialization.cpp
|
||||||
src/rclcpp/serialized_message.cpp
|
src/rclcpp/serialized_message.cpp
|
||||||
src/rclcpp/service.cpp
|
src/rclcpp/service.cpp
|
||||||
@@ -259,4 +266,8 @@ if(TEST cppcheck)
|
|||||||
set_tests_properties(cppcheck PROPERTIES TIMEOUT 500)
|
set_tests_properties(cppcheck PROPERTIES TIMEOUT 500)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(TEST cpplint)
|
||||||
|
set_tests_properties(cpplint PROPERTIES TIMEOUT 180)
|
||||||
|
endif()
|
||||||
|
|
||||||
ament_generate_version_header(${PROJECT_NAME})
|
ament_generate_version_header(${PROJECT_NAME})
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#ifndef RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
|
#ifndef RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
|
||||||
#define RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
|
#define RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "rcl/allocator.h"
|
#include "rcl/allocator.h"
|
||||||
@@ -39,6 +40,22 @@ void * retyped_allocate(size_t size, void * untyped_allocator)
|
|||||||
return std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
|
return std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Alloc>
|
||||||
|
void * retyped_zero_allocate(size_t number_of_elem, size_t size_of_elem, void * untyped_allocator)
|
||||||
|
{
|
||||||
|
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
|
||||||
|
if (!typed_allocator) {
|
||||||
|
throw std::runtime_error("Received incorrect allocator type");
|
||||||
|
}
|
||||||
|
size_t size = number_of_elem * size_of_elem;
|
||||||
|
void * allocated_memory =
|
||||||
|
std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
|
||||||
|
if (allocated_memory) {
|
||||||
|
std::memset(allocated_memory, 0, size);
|
||||||
|
}
|
||||||
|
return allocated_memory;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T, typename Alloc>
|
template<typename T, typename Alloc>
|
||||||
void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
|
void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
|
||||||
{
|
{
|
||||||
@@ -73,6 +90,7 @@ rcl_allocator_t get_rcl_allocator(Alloc & allocator)
|
|||||||
rcl_allocator_t rcl_allocator = rcl_get_default_allocator();
|
rcl_allocator_t rcl_allocator = rcl_get_default_allocator();
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
rcl_allocator.allocate = &retyped_allocate<Alloc>;
|
rcl_allocator.allocate = &retyped_allocate<Alloc>;
|
||||||
|
rcl_allocator.zero_allocate = &retyped_zero_allocate<Alloc>;
|
||||||
rcl_allocator.deallocate = &retyped_deallocate<T, Alloc>;
|
rcl_allocator.deallocate = &retyped_deallocate<T, Alloc>;
|
||||||
rcl_allocator.reallocate = &retyped_reallocate<T, Alloc>;
|
rcl_allocator.reallocate = &retyped_reallocate<T, Alloc>;
|
||||||
rcl_allocator.state = &allocator;
|
rcl_allocator.state = &allocator;
|
||||||
|
|||||||
@@ -191,10 +191,14 @@ public:
|
|||||||
#ifndef TRACETOOLS_DISABLED
|
#ifndef TRACETOOLS_DISABLED
|
||||||
std::visit(
|
std::visit(
|
||||||
[this](auto && arg) {
|
[this](auto && arg) {
|
||||||
TRACEPOINT(
|
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
|
||||||
rclcpp_callback_register,
|
char * symbol = tracetools::get_symbol(arg);
|
||||||
static_cast<const void *>(this),
|
DO_TRACEPOINT(
|
||||||
tracetools::get_symbol(arg));
|
rclcpp_callback_register,
|
||||||
|
static_cast<const void *>(this),
|
||||||
|
symbol);
|
||||||
|
std::free(symbol);
|
||||||
|
}
|
||||||
}, callback_);
|
}, callback_);
|
||||||
#endif // TRACETOOLS_DISABLED
|
#endif // TRACETOOLS_DISABLED
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -965,10 +965,14 @@ public:
|
|||||||
#ifndef TRACETOOLS_DISABLED
|
#ifndef TRACETOOLS_DISABLED
|
||||||
std::visit(
|
std::visit(
|
||||||
[this](auto && callback) {
|
[this](auto && callback) {
|
||||||
TRACEPOINT(
|
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
|
||||||
rclcpp_callback_register,
|
char * symbol = tracetools::get_symbol(callback);
|
||||||
static_cast<const void *>(this),
|
DO_TRACEPOINT(
|
||||||
tracetools::get_symbol(callback));
|
rclcpp_callback_register,
|
||||||
|
static_cast<const void *>(this),
|
||||||
|
symbol);
|
||||||
|
std::free(symbol);
|
||||||
|
}
|
||||||
}, callback_variant_);
|
}, callback_variant_);
|
||||||
#endif // TRACETOOLS_DISABLED
|
#endif // TRACETOOLS_DISABLED
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,14 @@
|
|||||||
#define RCLCPP__CALLBACK_GROUP_HPP_
|
#define RCLCPP__CALLBACK_GROUP_HPP_
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "rclcpp/client.hpp"
|
#include "rclcpp/client.hpp"
|
||||||
|
#include "rclcpp/context.hpp"
|
||||||
|
#include "rclcpp/guard_condition.hpp"
|
||||||
#include "rclcpp/publisher_base.hpp"
|
#include "rclcpp/publisher_base.hpp"
|
||||||
#include "rclcpp/service.hpp"
|
#include "rclcpp/service.hpp"
|
||||||
#include "rclcpp/subscription_base.hpp"
|
#include "rclcpp/subscription_base.hpp"
|
||||||
@@ -95,6 +98,10 @@ public:
|
|||||||
CallbackGroupType group_type,
|
CallbackGroupType group_type,
|
||||||
bool automatically_add_to_executor_with_node = true);
|
bool automatically_add_to_executor_with_node = true);
|
||||||
|
|
||||||
|
/// Default destructor.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
~CallbackGroup();
|
||||||
|
|
||||||
template<typename Function>
|
template<typename Function>
|
||||||
rclcpp::SubscriptionBase::SharedPtr
|
rclcpp::SubscriptionBase::SharedPtr
|
||||||
find_subscription_ptrs_if(Function func) const
|
find_subscription_ptrs_if(Function func) const
|
||||||
@@ -171,6 +178,16 @@ public:
|
|||||||
bool
|
bool
|
||||||
automatically_add_to_executor_with_node() const;
|
automatically_add_to_executor_with_node() const;
|
||||||
|
|
||||||
|
/// Defer creating the notify guard condition and return it.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rclcpp::GuardCondition::SharedPtr
|
||||||
|
get_notify_guard_condition(const rclcpp::Context::SharedPtr context_ptr);
|
||||||
|
|
||||||
|
/// Trigger the notify guard condition.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
trigger_notify_guard_condition();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
RCLCPP_DISABLE_COPY(CallbackGroup)
|
RCLCPP_DISABLE_COPY(CallbackGroup)
|
||||||
|
|
||||||
@@ -213,6 +230,9 @@ protected:
|
|||||||
std::vector<rclcpp::Waitable::WeakPtr> waitable_ptrs_;
|
std::vector<rclcpp::Waitable::WeakPtr> waitable_ptrs_;
|
||||||
std::atomic_bool can_be_taken_from_;
|
std::atomic_bool can_be_taken_from_;
|
||||||
const bool automatically_add_to_executor_with_node_;
|
const bool automatically_add_to_executor_with_node_;
|
||||||
|
// defer the creation of the guard condition
|
||||||
|
std::shared_ptr<rclcpp::GuardCondition> notify_guard_condition_ = nullptr;
|
||||||
|
std::recursive_mutex notify_guard_condition_mutex_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename TypeT, typename Function>
|
template<typename TypeT, typename Function>
|
||||||
|
|||||||
@@ -16,14 +16,15 @@
|
|||||||
#define RCLCPP__CLIENT_HPP_
|
#define RCLCPP__CLIENT_HPP_
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <unordered_map>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional> // NOLINT, cpplint doesn't think this is a cpp std header
|
#include <optional> // NOLINT, cpplint doesn't think this is a cpp std header
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <unordered_map>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <variant> // NOLINT
|
#include <variant> // NOLINT
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -31,8 +32,10 @@
|
|||||||
#include "rcl/client.h"
|
#include "rcl/client.h"
|
||||||
#include "rcl/error_handling.h"
|
#include "rcl/error_handling.h"
|
||||||
#include "rcl/event_callback.h"
|
#include "rcl/event_callback.h"
|
||||||
|
#include "rcl/service_introspection.h"
|
||||||
#include "rcl/wait.h"
|
#include "rcl/wait.h"
|
||||||
|
|
||||||
|
#include "rclcpp/clock.hpp"
|
||||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||||
#include "rclcpp/exceptions.hpp"
|
#include "rclcpp/exceptions.hpp"
|
||||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||||
@@ -130,7 +133,7 @@ public:
|
|||||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph);
|
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph);
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
virtual ~ClientBase();
|
virtual ~ClientBase() = default;
|
||||||
|
|
||||||
/// Take the next response for this client as a type erased pointer.
|
/// Take the next response for this client as a type erased pointer.
|
||||||
/**
|
/**
|
||||||
@@ -312,7 +315,7 @@ public:
|
|||||||
// This two-step setting, prevents a gap where the old std::function has
|
// This two-step setting, prevents a gap where the old std::function has
|
||||||
// been replaced but the middleware hasn't been told about the new one yet.
|
// been replaced but the middleware hasn't been told about the new one yet.
|
||||||
set_on_new_response_callback(
|
set_on_new_response_callback(
|
||||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||||
static_cast<const void *>(&new_callback));
|
static_cast<const void *>(&new_callback));
|
||||||
|
|
||||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||||
@@ -320,7 +323,8 @@ public:
|
|||||||
|
|
||||||
// Set it again, now using the permanent storage.
|
// Set it again, now using the permanent storage.
|
||||||
set_on_new_response_callback(
|
set_on_new_response_callback(
|
||||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
rclcpp::detail::cpp_callback_trampoline<
|
||||||
|
decltype(on_new_response_callback_), const void *, size_t>,
|
||||||
static_cast<const void *>(&on_new_response_callback_));
|
static_cast<const void *>(&on_new_response_callback_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,15 +470,13 @@ public:
|
|||||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||||
const std::string & service_name,
|
const std::string & service_name,
|
||||||
rcl_client_options_t & client_options)
|
rcl_client_options_t & client_options)
|
||||||
: ClientBase(node_base, node_graph)
|
: ClientBase(node_base, node_graph),
|
||||||
|
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
|
||||||
{
|
{
|
||||||
using rosidl_typesupport_cpp::get_service_type_support_handle;
|
|
||||||
auto service_type_support_handle =
|
|
||||||
get_service_type_support_handle<ServiceT>();
|
|
||||||
rcl_ret_t ret = rcl_client_init(
|
rcl_ret_t ret = rcl_client_init(
|
||||||
this->get_client_handle().get(),
|
this->get_client_handle().get(),
|
||||||
this->get_rcl_node_handle(),
|
this->get_rcl_node_handle(),
|
||||||
service_type_support_handle,
|
srv_type_support_handle_,
|
||||||
service_name.c_str(),
|
service_name.c_str(),
|
||||||
&client_options);
|
&client_options);
|
||||||
if (ret != RCL_RET_OK) {
|
if (ret != RCL_RET_OK) {
|
||||||
@@ -769,7 +771,9 @@ public:
|
|||||||
auto old_size = pending_requests_.size();
|
auto old_size = pending_requests_.size();
|
||||||
for (auto it = pending_requests_.begin(), last = pending_requests_.end(); it != last; ) {
|
for (auto it = pending_requests_.begin(), last = pending_requests_.end(); it != last; ) {
|
||||||
if (it->second.first < time_point) {
|
if (it->second.first < time_point) {
|
||||||
pruned_requests->push_back(it->first);
|
if (pruned_requests) {
|
||||||
|
pruned_requests->push_back(it->first);
|
||||||
|
}
|
||||||
it = pending_requests_.erase(it);
|
it = pending_requests_.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
@@ -778,6 +782,33 @@ public:
|
|||||||
return old_size - pending_requests_.size();
|
return old_size - pending_requests_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure client introspection.
|
||||||
|
/**
|
||||||
|
* \param[in] clock clock to use to generate introspection timestamps
|
||||||
|
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
|
||||||
|
* \param[in] introspection_state the state to set introspection to
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
configure_introspection(
|
||||||
|
Clock::SharedPtr clock, const QoS & qos_service_event_pub,
|
||||||
|
rcl_service_introspection_state_t introspection_state)
|
||||||
|
{
|
||||||
|
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
|
||||||
|
pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
|
||||||
|
|
||||||
|
rcl_ret_t ret = rcl_client_configure_service_introspection(
|
||||||
|
client_handle_.get(),
|
||||||
|
node_handle_.get(),
|
||||||
|
clock->get_clock_handle(),
|
||||||
|
srv_type_support_handle_,
|
||||||
|
pub_opts,
|
||||||
|
introspection_state);
|
||||||
|
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure client introspection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
|
using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
|
||||||
using CallbackWithRequestTypeValueVariant = std::tuple<
|
using CallbackWithRequestTypeValueVariant = std::tuple<
|
||||||
@@ -792,16 +823,14 @@ protected:
|
|||||||
async_send_request_impl(const Request & request, CallbackInfoVariant value)
|
async_send_request_impl(const Request & request, CallbackInfoVariant value)
|
||||||
{
|
{
|
||||||
int64_t sequence_number;
|
int64_t sequence_number;
|
||||||
|
std::lock_guard<std::mutex> lock(pending_requests_mutex_);
|
||||||
rcl_ret_t ret = rcl_send_request(get_client_handle().get(), &request, &sequence_number);
|
rcl_ret_t ret = rcl_send_request(get_client_handle().get(), &request, &sequence_number);
|
||||||
if (RCL_RET_OK != ret) {
|
if (RCL_RET_OK != ret) {
|
||||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
|
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
|
||||||
}
|
}
|
||||||
{
|
pending_requests_.try_emplace(
|
||||||
std::lock_guard<std::mutex> lock(pending_requests_mutex_);
|
sequence_number,
|
||||||
pending_requests_.try_emplace(
|
std::make_pair(std::chrono::system_clock::now(), std::move(value)));
|
||||||
sequence_number,
|
|
||||||
std::make_pair(std::chrono::system_clock::now(), std::move(value)));
|
|
||||||
}
|
|
||||||
return sequence_number;
|
return sequence_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -830,6 +859,9 @@ protected:
|
|||||||
CallbackInfoVariant>>
|
CallbackInfoVariant>>
|
||||||
pending_requests_;
|
pending_requests_;
|
||||||
std::mutex pending_requests_mutex_;
|
std::mutex pending_requests_mutex_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const rosidl_service_type_support_t * srv_type_support_handle_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
Time
|
Time
|
||||||
now();
|
now() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleep until a specified Time, according to clock type.
|
* Sleep until a specified Time, according to clock type.
|
||||||
@@ -137,6 +137,51 @@ public:
|
|||||||
Duration rel_time,
|
Duration rel_time,
|
||||||
Context::SharedPtr context = contexts::get_global_default_context());
|
Context::SharedPtr context = contexts::get_global_default_context());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the clock is started.
|
||||||
|
*
|
||||||
|
* A started clock is a clock that reflects non-zero time.
|
||||||
|
* Typically a clock will be unstarted if it is using RCL_ROS_TIME with ROS time and
|
||||||
|
* nothing has been published on the clock topic yet.
|
||||||
|
*
|
||||||
|
* \return true if clock is started
|
||||||
|
* \throws std::runtime_error if the clock is not rcl_clock_valid
|
||||||
|
*/
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
started();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait until clock to start.
|
||||||
|
*
|
||||||
|
* \rclcpp::Clock::started
|
||||||
|
* \param context the context to wait in
|
||||||
|
* \return true if clock was already started or became started
|
||||||
|
* \throws std::runtime_error if the context is invalid or clock is not rcl_clock_valid
|
||||||
|
*/
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
wait_until_started(Context::SharedPtr context = contexts::get_global_default_context());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for clock to start, with timeout.
|
||||||
|
*
|
||||||
|
* The timeout is waited in steady time.
|
||||||
|
*
|
||||||
|
* \rclcpp::Clock::started
|
||||||
|
* \param timeout the maximum time to wait for.
|
||||||
|
* \param context the context to wait in.
|
||||||
|
* \param wait_tick_ns the time to wait between each iteration of the wait loop (in nanoseconds).
|
||||||
|
* \return true if clock was or became valid
|
||||||
|
* \throws std::runtime_error if the context is invalid or clock is not rcl_clock_valid
|
||||||
|
*/
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
wait_until_started(
|
||||||
|
const rclcpp::Duration & timeout,
|
||||||
|
Context::SharedPtr context = contexts::get_global_default_context(),
|
||||||
|
const rclcpp::Duration & wait_tick_ns = rclcpp::Duration(0, static_cast<uint32_t>(1e7)));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the clock of the type `RCL_ROS_TIME` is active.
|
* Returns the clock of the type `RCL_ROS_TIME` is active.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -65,8 +65,11 @@ using PreShutdownCallbackHandle = ShutdownCallbackHandle;
|
|||||||
/// Context which encapsulates shared state between nodes and other similar entities.
|
/// Context which encapsulates shared state between nodes and other similar entities.
|
||||||
/**
|
/**
|
||||||
* A context also represents the lifecycle between init and shutdown of rclcpp.
|
* A context also represents the lifecycle between init and shutdown of rclcpp.
|
||||||
* It is often used in conjunction with rclcpp::init, or rclcpp::init_local,
|
* Nodes may be attached to a particular context by passing to the rclcpp::Node
|
||||||
* and rclcpp::shutdown.
|
* constructor a rclcpp::NodeOptions instance in which the Context is set via
|
||||||
|
* rclcpp::NodeOptions::context.
|
||||||
|
* Nodes will be automatically removed from the context when destructed.
|
||||||
|
* Contexts may be shutdown by calling rclcpp::shutdown.
|
||||||
*/
|
*/
|
||||||
class Context : public std::enable_shared_from_this<Context>
|
class Context : public std::enable_shared_from_this<Context>
|
||||||
{
|
{
|
||||||
@@ -376,10 +379,10 @@ private:
|
|||||||
// attempt to acquire another sub context.
|
// attempt to acquire another sub context.
|
||||||
std::recursive_mutex sub_contexts_mutex_;
|
std::recursive_mutex sub_contexts_mutex_;
|
||||||
|
|
||||||
std::unordered_set<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
|
std::vector<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
|
||||||
mutable std::mutex on_shutdown_callbacks_mutex_;
|
mutable std::mutex on_shutdown_callbacks_mutex_;
|
||||||
|
|
||||||
std::unordered_set<std::shared_ptr<PreShutdownCallback>> pre_shutdown_callbacks_;
|
std::vector<std::shared_ptr<PreShutdownCallback>> pre_shutdown_callbacks_;
|
||||||
mutable std::mutex pre_shutdown_callbacks_mutex_;
|
mutable std::mutex pre_shutdown_callbacks_mutex_;
|
||||||
|
|
||||||
/// Condition variable for timed sleep (see sleep_for).
|
/// Condition variable for timed sleep (see sleep_for).
|
||||||
@@ -398,20 +401,22 @@ private:
|
|||||||
|
|
||||||
using ShutdownCallback = ShutdownCallbackHandle::ShutdownCallbackType;
|
using ShutdownCallback = ShutdownCallbackHandle::ShutdownCallbackType;
|
||||||
|
|
||||||
|
template<ShutdownType shutdown_type>
|
||||||
RCLCPP_LOCAL
|
RCLCPP_LOCAL
|
||||||
ShutdownCallbackHandle
|
ShutdownCallbackHandle
|
||||||
add_shutdown_callback(
|
add_shutdown_callback(
|
||||||
ShutdownType shutdown_type,
|
|
||||||
ShutdownCallback callback);
|
ShutdownCallback callback);
|
||||||
|
|
||||||
|
template<ShutdownType shutdown_type>
|
||||||
RCLCPP_LOCAL
|
RCLCPP_LOCAL
|
||||||
bool
|
bool
|
||||||
remove_shutdown_callback(
|
remove_shutdown_callback(
|
||||||
ShutdownType shutdown_type,
|
|
||||||
const ShutdownCallbackHandle & callback_handle);
|
const ShutdownCallbackHandle & callback_handle);
|
||||||
|
|
||||||
|
template<ShutdownType shutdown_type>
|
||||||
|
RCLCPP_LOCAL
|
||||||
std::vector<rclcpp::Context::ShutdownCallback>
|
std::vector<rclcpp::Context::ShutdownCallback>
|
||||||
get_shutdown_callback(ShutdownType shutdown_type) const;
|
get_shutdown_callback() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Return a copy of the list of context shared pointers.
|
/// Return a copy of the list of context shared pointers.
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace detail
|
|||||||
* so no exceptions should be thrown at this point, and doing so results in
|
* so no exceptions should be thrown at this point, and doing so results in
|
||||||
* undefined behavior.
|
* undefined behavior.
|
||||||
*
|
*
|
||||||
|
* \tparam UserDataRealT Declared type of the passed function
|
||||||
* \tparam UserDataT Deduced type based on what is passed for user data,
|
* \tparam UserDataT Deduced type based on what is passed for user data,
|
||||||
* usually this type is either `void *` or `const void *`.
|
* usually this type is either `void *` or `const void *`.
|
||||||
* \tparam Args the arguments being passed to the callback
|
* \tparam Args the arguments being passed to the callback
|
||||||
@@ -50,6 +51,7 @@ namespace detail
|
|||||||
* \returns whatever the callback returns, if anything
|
* \returns whatever the callback returns, if anything
|
||||||
*/
|
*/
|
||||||
template<
|
template<
|
||||||
|
typename UserDataRealT,
|
||||||
typename UserDataT,
|
typename UserDataT,
|
||||||
typename ... Args,
|
typename ... Args,
|
||||||
typename ReturnT = void
|
typename ReturnT = void
|
||||||
@@ -57,7 +59,7 @@ template<
|
|||||||
ReturnT
|
ReturnT
|
||||||
cpp_callback_trampoline(UserDataT user_data, Args ... args) noexcept
|
cpp_callback_trampoline(UserDataT user_data, Args ... args) noexcept
|
||||||
{
|
{
|
||||||
auto & actual_callback = *reinterpret_cast<const std::function<ReturnT(Args...)> *>(user_data);
|
auto & actual_callback = *static_cast<const UserDataRealT *>(user_data);
|
||||||
return actual_callback(args ...);
|
return actual_callback(args ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
47
rclcpp/include/rclcpp/detail/template_contains.hpp
Normal file
47
rclcpp/include/rclcpp/detail/template_contains.hpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
|
||||||
|
#define RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Template meta-function that checks if a given T is contained in the list Us.
|
||||||
|
template<typename T, typename ... Us>
|
||||||
|
struct template_contains;
|
||||||
|
|
||||||
|
template<typename ... Args>
|
||||||
|
inline constexpr bool template_contains_v = template_contains<Args ...>::value;
|
||||||
|
|
||||||
|
template<typename T, typename NextT, typename ... Us>
|
||||||
|
struct template_contains<T, NextT, Us ...>
|
||||||
|
{
|
||||||
|
enum { value = (std::is_same_v<T, NextT>|| template_contains_v<T, Us ...>)};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct template_contains<T>
|
||||||
|
{
|
||||||
|
enum { value = false };
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
|
||||||
49
rclcpp/include/rclcpp/detail/template_unique.hpp
Normal file
49
rclcpp/include/rclcpp/detail/template_unique.hpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
|
||||||
|
#define RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "rclcpp/detail/template_contains.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Template meta-function that checks if a given list Ts contains unique types.
|
||||||
|
template<typename ... Ts>
|
||||||
|
struct template_unique;
|
||||||
|
|
||||||
|
template<typename ... Args>
|
||||||
|
inline constexpr bool template_unique_v = template_unique<Args ...>::value;
|
||||||
|
|
||||||
|
template<typename NextT, typename ... Ts>
|
||||||
|
struct template_unique<NextT, Ts ...>
|
||||||
|
{
|
||||||
|
enum { value = !template_contains_v<NextT, Ts ...>&& template_unique_v<Ts ...>};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct template_unique<T>
|
||||||
|
{
|
||||||
|
enum { value = true };
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
|
||||||
176
rclcpp/include/rclcpp/dynamic_subscription.hpp
Normal file
176
rclcpp/include/rclcpp/dynamic_subscription.hpp
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
|
||||||
|
#define RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
|
||||||
|
|
||||||
|
#include <rosidl_dynamic_typesupport/identifier.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rcpputils/shared_library.hpp"
|
||||||
|
|
||||||
|
#include "rclcpp/callback_group.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type_support.hpp"
|
||||||
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||||
|
#include "rclcpp/qos.hpp"
|
||||||
|
#include "rclcpp/serialized_message.hpp"
|
||||||
|
#include "rclcpp/subscription_base.hpp"
|
||||||
|
#include "rclcpp/typesupport_helpers.hpp"
|
||||||
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
|
||||||
|
/// %Subscription for messages whose type descriptions are obtained at runtime.
|
||||||
|
/**
|
||||||
|
* Since the type is not known at compile time, this is not a template, and the dynamic library
|
||||||
|
* containing type support information has to be identified and loaded based on the type name.
|
||||||
|
*
|
||||||
|
* NOTE(methylDragon): No considerations for intra-process handling are made.
|
||||||
|
*/
|
||||||
|
class DynamicSubscription : public rclcpp::SubscriptionBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// cppcheck-suppress unknownMacro
|
||||||
|
RCLCPP_SMART_PTR_DEFINITIONS(DynamicSubscription)
|
||||||
|
|
||||||
|
template<typename AllocatorT = std::allocator<void>>
|
||||||
|
DynamicSubscription(
|
||||||
|
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessageTypeSupport::SharedPtr type_support,
|
||||||
|
const std::string & topic_name,
|
||||||
|
const rclcpp::QoS & qos,
|
||||||
|
std::function<void(
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription &
|
||||||
|
)> callback,
|
||||||
|
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||||
|
bool use_take_dynamic_message = true)
|
||||||
|
: SubscriptionBase(
|
||||||
|
node_base,
|
||||||
|
type_support->get_const_rosidl_message_type_support(),
|
||||||
|
topic_name,
|
||||||
|
options.to_rcl_subscription_options(
|
||||||
|
qos),
|
||||||
|
options.event_callbacks,
|
||||||
|
options.use_default_callbacks,
|
||||||
|
use_take_dynamic_message ? SubscriptionType::DYNAMIC_MESSAGE_DIRECT : SubscriptionType::DYNAMIC_MESSAGE_FROM_SERIALIZED), // NOLINT
|
||||||
|
ts_(type_support),
|
||||||
|
callback_(callback),
|
||||||
|
serialization_support_(nullptr),
|
||||||
|
dynamic_message_(nullptr),
|
||||||
|
dynamic_message_type_(nullptr)
|
||||||
|
{
|
||||||
|
if (!type_support) {
|
||||||
|
throw std::runtime_error("DynamicMessageTypeSupport cannot be nullptr!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type_support->get_const_rosidl_message_type_support().typesupport_identifier !=
|
||||||
|
rosidl_get_dynamic_typesupport_identifier())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"DynamicSubscription must use dynamic type introspection type support!");
|
||||||
|
}
|
||||||
|
|
||||||
|
serialization_support_ = type_support->get_shared_dynamic_serialization_support();
|
||||||
|
dynamic_message_type_ = type_support->get_shared_dynamic_message_type()->clone_shared();
|
||||||
|
dynamic_message_ = type_support->get_shared_dynamic_message()->clone_shared();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(methylDragon):
|
||||||
|
/// Deferred type description constructor, only usable if the middleware implementation supports
|
||||||
|
/// type discovery
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual ~DynamicSubscription() = default;
|
||||||
|
|
||||||
|
// Same as create_serialized_message() as the subscription is to serialized_messages only
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
std::shared_ptr<void> create_message() override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
std::shared_ptr<rclcpp::SerializedMessage> create_serialized_message() override;
|
||||||
|
|
||||||
|
/// Cast the message to a rclcpp::SerializedMessage and call the callback.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void handle_message(
|
||||||
|
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) override;
|
||||||
|
|
||||||
|
/// Handle dispatching rclcpp::SerializedMessage to user callback.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
handle_serialized_message(
|
||||||
|
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||||
|
const rclcpp::MessageInfo & message_info) override;
|
||||||
|
|
||||||
|
/// This function is currently not implemented.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void handle_loaned_message(
|
||||||
|
void * loaned_message, const rclcpp::MessageInfo & message_info) override;
|
||||||
|
|
||||||
|
// Same as return_serialized_message() as the subscription is to serialized_messages only
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void return_message(std::shared_ptr<void> & message) override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
|
||||||
|
|
||||||
|
|
||||||
|
// DYNAMIC TYPE ==================================================================================
|
||||||
|
// TODO(methylDragon): Reorder later
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
|
||||||
|
get_shared_dynamic_message_type() override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr get_shared_dynamic_message() override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
|
||||||
|
get_shared_dynamic_serialization_support() override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void return_dynamic_message(
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void handle_dynamic_message(
|
||||||
|
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
|
||||||
|
const rclcpp::MessageInfo & message_info) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RCLCPP_DISABLE_COPY(DynamicSubscription)
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessageTypeSupport::SharedPtr ts_;
|
||||||
|
std::function<void(
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription &
|
||||||
|
)> callback_;
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr dynamic_message_;
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr dynamic_message_type_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
|
||||||
@@ -0,0 +1,327 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
|
||||||
|
#define RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
|
||||||
|
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define __DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN(ValueT, FunctionT) \
|
||||||
|
template<> \
|
||||||
|
ValueT \
|
||||||
|
DynamicMessage::get_value<ValueT>(rosidl_dynamic_typesupport_member_id_t id) \
|
||||||
|
{ \
|
||||||
|
ValueT out; \
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_ ## FunctionT ## _value( \
|
||||||
|
&rosidl_dynamic_data_, id, &out); \
|
||||||
|
return out; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
|
||||||
|
template<> \
|
||||||
|
ValueT \
|
||||||
|
DynamicMessage::get_value<ValueT>(const std::string & name) \
|
||||||
|
{ \
|
||||||
|
return get_value<ValueT>(get_member_id(name)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN(ValueT, FunctionT) \
|
||||||
|
template<> \
|
||||||
|
void \
|
||||||
|
DynamicMessage::set_value<ValueT>(rosidl_dynamic_typesupport_member_id_t id, ValueT value) \
|
||||||
|
{ \
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_set_ ## FunctionT ## _value( \
|
||||||
|
&rosidl_dynamic_data_, id, value); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
|
||||||
|
template<> \
|
||||||
|
void \
|
||||||
|
DynamicMessage::set_value<ValueT>(const std::string & name, ValueT value) \
|
||||||
|
{ \
|
||||||
|
set_value<ValueT>(get_member_id(name), value); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __DYNAMIC_MESSAGE_INSERT_VALUE(ValueT, FunctionT) \
|
||||||
|
template<> \
|
||||||
|
rosidl_dynamic_typesupport_member_id_t \
|
||||||
|
DynamicMessage::insert_value<ValueT>(ValueT value) \
|
||||||
|
{ \
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out; \
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_ ## FunctionT ## _value( \
|
||||||
|
&rosidl_dynamic_data_, value, &out); \
|
||||||
|
return out; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DYNAMIC_MESSAGE_DEFINITIONS(ValueT, FunctionT) \
|
||||||
|
__DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN(ValueT, FunctionT) \
|
||||||
|
__DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
|
||||||
|
__DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN(ValueT, FunctionT) \
|
||||||
|
__DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
|
||||||
|
__DYNAMIC_MESSAGE_INSERT_VALUE(ValueT, FunctionT)
|
||||||
|
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace dynamic_typesupport
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
|
||||||
|
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
|
||||||
|
*
|
||||||
|
* Explicitly:
|
||||||
|
* - Basic types: bool, byte, char
|
||||||
|
* - Float types: float, double
|
||||||
|
* - Int types: int8_t, int16_t, int32_t, int64_t
|
||||||
|
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
|
||||||
|
* - String types: std::string, std::u16string
|
||||||
|
*/
|
||||||
|
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(bool, bool);
|
||||||
|
// DYNAMIC_MESSAGE_DEFINITIONS(std::byte, byte);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(char, char);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(float, float32);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(double, float64);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(int8_t, int8);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(int16_t, int16);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(int32_t, int32);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(int64_t, int64);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(uint8_t, uint8);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(uint16_t, uint16);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(uint32_t, uint32);
|
||||||
|
DYNAMIC_MESSAGE_DEFINITIONS(uint64_t, uint64);
|
||||||
|
// DYNAMIC_MESSAGE_DEFINITIONS(std::string, std::string);
|
||||||
|
// DYNAMIC_MESSAGE_DEFINITIONS(std::u16string, std::u16string);
|
||||||
|
|
||||||
|
// Byte and String getters have a different implementation and are defined below
|
||||||
|
|
||||||
|
|
||||||
|
// BYTE ============================================================================================
|
||||||
|
template<>
|
||||||
|
std::byte
|
||||||
|
DynamicMessage::get_value<std::byte>(rosidl_dynamic_typesupport_member_id_t id)
|
||||||
|
{
|
||||||
|
unsigned char out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_byte_value(&get_rosidl_dynamic_data(), id, &out);
|
||||||
|
return static_cast<std::byte>(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::byte
|
||||||
|
DynamicMessage::get_value<std::byte>(const std::string & name)
|
||||||
|
{
|
||||||
|
return get_value<std::byte>(get_member_id(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
DynamicMessage::set_value<std::byte>(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::byte value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_set_byte_value(
|
||||||
|
&rosidl_dynamic_data_, id, static_cast<unsigned char>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
DynamicMessage::set_value<std::byte>(const std::string & name, const std::byte value)
|
||||||
|
{
|
||||||
|
set_value<std::byte>(get_member_id(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_value<std::byte>(const std::byte value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_byte_value(
|
||||||
|
&rosidl_dynamic_data_, static_cast<unsigned char>(value), &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// STRINGS =========================================================================================
|
||||||
|
template<>
|
||||||
|
std::string
|
||||||
|
DynamicMessage::get_value<std::string>(rosidl_dynamic_typesupport_member_id_t id)
|
||||||
|
{
|
||||||
|
size_t buf_length;
|
||||||
|
char * buf = nullptr;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_string_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &buf, &buf_length);
|
||||||
|
auto out = std::string(buf, buf_length);
|
||||||
|
delete buf;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::u16string
|
||||||
|
DynamicMessage::get_value<std::u16string>(rosidl_dynamic_typesupport_member_id_t id)
|
||||||
|
{
|
||||||
|
size_t buf_length;
|
||||||
|
char16_t * buf = nullptr;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_wstring_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &buf, &buf_length);
|
||||||
|
auto out = std::u16string(buf, buf_length);
|
||||||
|
delete buf;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::string
|
||||||
|
DynamicMessage::get_value<std::string>(const std::string & name)
|
||||||
|
{
|
||||||
|
return get_value<std::string>(get_member_id(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
std::u16string
|
||||||
|
DynamicMessage::get_value<std::u16string>(const std::string & name)
|
||||||
|
{
|
||||||
|
return get_value<std::u16string>(get_member_id(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
DynamicMessage::set_value<std::string>(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_set_string_value(
|
||||||
|
&rosidl_dynamic_data_, id, value.c_str(), value.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
DynamicMessage::set_value<std::u16string>(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_set_wstring_value(
|
||||||
|
&rosidl_dynamic_data_, id, value.c_str(), value.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
DynamicMessage::set_value<std::string>(const std::string & name, const std::string value)
|
||||||
|
{
|
||||||
|
set_value<std::string>(get_member_id(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void
|
||||||
|
DynamicMessage::set_value<std::u16string>(const std::string & name, const std::u16string value)
|
||||||
|
{
|
||||||
|
set_value<std::u16string>(get_member_id(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_value<std::string>(const std::string value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_string_value(
|
||||||
|
&rosidl_dynamic_data_, value.c_str(), value.size(), &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_value<std::u16string>(const std::u16string value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_wstring_value(
|
||||||
|
&rosidl_dynamic_data_, value.c_str(), value.size(), &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// THROW FOR UNSUPPORTED TYPES =====================================================================
|
||||||
|
template<typename ValueT>
|
||||||
|
ValueT
|
||||||
|
DynamicMessage::get_value(rosidl_dynamic_typesupport_member_id_t id)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError("get_value is not implemented for input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ValueT>
|
||||||
|
ValueT
|
||||||
|
DynamicMessage::get_value(const std::string & name)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError("get_value is not implemented for input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ValueT>
|
||||||
|
void
|
||||||
|
DynamicMessage::set_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, ValueT value)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError("set_value is not implemented for input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ValueT>
|
||||||
|
void
|
||||||
|
DynamicMessage::set_value(const std::string & name, ValueT value)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError("set_value is not implemented for input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ValueT>
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_value(ValueT value)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError("insert_value is not implemented for input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace dynamic_typesupport
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#undef __DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN
|
||||||
|
#undef __DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN
|
||||||
|
#undef __DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN
|
||||||
|
#undef __DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN
|
||||||
|
#undef __DYNAMIC_MESSAGE_INSERT_VALUE
|
||||||
|
#undef DYNAMIC_MESSAGE_DEFINITIONS
|
||||||
|
|
||||||
|
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
|
||||||
|
#define RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
|
||||||
|
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN(MemberT, FunctionT) \
|
||||||
|
template<> \
|
||||||
|
void \
|
||||||
|
DynamicMessageTypeBuilder::add_member<MemberT>( \
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, \
|
||||||
|
const std::string & name, \
|
||||||
|
const std::string & default_value) \
|
||||||
|
{ \
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _member( \
|
||||||
|
&rosidl_dynamic_type_builder_, \
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size()); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN(MemberT, FunctionT) \
|
||||||
|
template<> \
|
||||||
|
void \
|
||||||
|
DynamicMessageTypeBuilder::add_array_member<MemberT>( \
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, \
|
||||||
|
size_t array_length, \
|
||||||
|
const std::string & default_value) \
|
||||||
|
{ \
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _array_member( \
|
||||||
|
&rosidl_dynamic_type_builder_, \
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(), \
|
||||||
|
array_length); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
|
||||||
|
template<> \
|
||||||
|
void \
|
||||||
|
DynamicMessageTypeBuilder::add_unbounded_sequence_member<MemberT>( \
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, \
|
||||||
|
const std::string & name, \
|
||||||
|
const std::string & default_value) \
|
||||||
|
{ \
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## \
|
||||||
|
_unbounded_sequence_member( \
|
||||||
|
&rosidl_dynamic_type_builder_, \
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size()); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
|
||||||
|
template<> \
|
||||||
|
void \
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_sequence_member<MemberT>( \
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, \
|
||||||
|
const std::string & name, \
|
||||||
|
size_t sequence_bound, \
|
||||||
|
const std::string & default_value) \
|
||||||
|
{ \
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _bounded_sequence_member( \
|
||||||
|
&rosidl_dynamic_type_builder_, \
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(), \
|
||||||
|
sequence_bound); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(MemberT, FunctionT) \
|
||||||
|
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN(MemberT, FunctionT) \
|
||||||
|
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN(MemberT, FunctionT) \
|
||||||
|
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
|
||||||
|
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
|
||||||
|
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace dynamic_typesupport
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
|
||||||
|
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
|
||||||
|
*
|
||||||
|
* Explicitly:
|
||||||
|
* - Basic types: bool, byte, char
|
||||||
|
* - Float types: float, double
|
||||||
|
* - Int types: int8_t, int16_t, int32_t, int64_t
|
||||||
|
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
|
||||||
|
* - String types: std::string, std::u16string
|
||||||
|
*/
|
||||||
|
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(bool, bool);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::byte, byte);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(char, char);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(float, float32);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(double, float64);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int8_t, int8);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int16_t, int16);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int32_t, int32);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int64_t, int64);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint8_t, uint8);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint16_t, uint16);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint32_t, uint32);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint64_t, uint64);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::string, string);
|
||||||
|
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::u16string, wstring);
|
||||||
|
|
||||||
|
|
||||||
|
// THROW FOR UNSUPPORTED TYPES =====================================================================
|
||||||
|
template<typename MemberT>
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id,
|
||||||
|
const std::string & name,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"add_member is not implemented for input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename MemberT>
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id,
|
||||||
|
const std::string & name,
|
||||||
|
size_t array_length, const std::string & default_value)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"add_array_member is not implemented for input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename MemberT>
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id,
|
||||||
|
const std::string & name,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"add_unbounded_sequence_member is not implemented for input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename MemberT>
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id,
|
||||||
|
const std::string & name,
|
||||||
|
size_t sequence_bound,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"add_bounded_sequence_member is not implemented for input type");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace dynamic_typesupport
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN
|
||||||
|
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN
|
||||||
|
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN
|
||||||
|
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN
|
||||||
|
#undef DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS
|
||||||
|
|
||||||
|
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
|
||||||
432
rclcpp/include/rclcpp/dynamic_typesupport/dynamic_message.hpp
Normal file
432
rclcpp/include/rclcpp/dynamic_typesupport/dynamic_message.hpp
Normal file
@@ -0,0 +1,432 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
|
||||||
|
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
|
||||||
|
|
||||||
|
#include <rcl/allocator.h>
|
||||||
|
#include <rcl/types.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace dynamic_typesupport
|
||||||
|
{
|
||||||
|
|
||||||
|
class DynamicMessageType;
|
||||||
|
class DynamicMessageTypeBuilder;
|
||||||
|
|
||||||
|
/// Utility wrapper class for rosidl_dynamic_typesupport_dynamic_data_t
|
||||||
|
/**
|
||||||
|
* This class:
|
||||||
|
* - Exposes getter methods for the struct
|
||||||
|
* - Exposes the underlying serialization support API
|
||||||
|
*
|
||||||
|
* Ownership:
|
||||||
|
* - This class borrows the rosidl_dynamic_typesupport_serialization_support_t stored in the passed
|
||||||
|
* DynamicSerializationSupport. So it cannot outlive the DynamicSerializationSupport.
|
||||||
|
* - The DynamicSerializationSupport's rosidl_dynamic_typesupport_serialization_support_t pointer
|
||||||
|
* must point to the same location in memory as the stored raw pointer!
|
||||||
|
*
|
||||||
|
* Note: This class is meant to map to the lower level rosidl_dynamic_typesupport_dynamic_data_t,
|
||||||
|
* even though rosidl_dynamic_typesupport_dynamic_data_t is equivalent to
|
||||||
|
* rosidl_dynamic_typesupport_dynamic_data_t, exposing the fundamental methods available to
|
||||||
|
* rosidl_dynamic_typesupport_dynamic_data_t, allowing the user to access the data's fields.
|
||||||
|
*/
|
||||||
|
class DynamicMessage : public std::enable_shared_from_this<DynamicMessage>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessage)
|
||||||
|
|
||||||
|
// CONSTRUCTION ==================================================================================
|
||||||
|
// Most constructors require a passed in DynamicSerializationSupport::SharedPtr, to extend the
|
||||||
|
// lifetime of the serialization support (if the constructor cannot otherwise get it from args).
|
||||||
|
//
|
||||||
|
// In cases where a dynamic data pointer is passed, the serialization support composed by
|
||||||
|
// the data should be the exact same object managed by the DynamicSerializationSupport,
|
||||||
|
// otherwise the lifetime management will not work properly.
|
||||||
|
|
||||||
|
/// Construct a new DynamicMessage with the provided dynamic type builder, using its allocator
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
explicit DynamicMessage(std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder);
|
||||||
|
|
||||||
|
/// Construct a new DynamicMessage with the provided dynamic type builder and allocator
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage(
|
||||||
|
std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder,
|
||||||
|
rcl_allocator_t allocator);
|
||||||
|
|
||||||
|
/// Construct a new DynamicMessage with the provided dynamic type, using its allocator
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
explicit DynamicMessage(std::shared_ptr<DynamicMessageType> dynamic_type);
|
||||||
|
|
||||||
|
/// Construct a new DynamicMessage with the provided dynamic type and allocator
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage(
|
||||||
|
std::shared_ptr<DynamicMessageType> dynamic_type,
|
||||||
|
rcl_allocator_t allocator);
|
||||||
|
|
||||||
|
/// Assume ownership of struct
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_dynamic_data);
|
||||||
|
|
||||||
|
/// Loaning constructor
|
||||||
|
/// Must only be called with a rosidl dynaimc data object obtained from loaning!
|
||||||
|
// NOTE(methylDragon): I'd put this in protected, but I need this exposed to
|
||||||
|
// enable_shared_from_this...
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage(
|
||||||
|
DynamicMessage::SharedPtr parent_data,
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_loaned_data);
|
||||||
|
|
||||||
|
// NOTE(methylDragon): Deliberately no constructor from description to nudge users towards using
|
||||||
|
// construction from dynamic type/builder, which is more efficient
|
||||||
|
|
||||||
|
/// Move constructor
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage(DynamicMessage && other) noexcept;
|
||||||
|
|
||||||
|
/// Move assignment
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage & operator=(DynamicMessage && other) noexcept;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual ~DynamicMessage();
|
||||||
|
|
||||||
|
|
||||||
|
// GETTERS =======================================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_serialization_library_identifier() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_name() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t &
|
||||||
|
get_rosidl_dynamic_data();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_data_t &
|
||||||
|
get_rosidl_dynamic_data() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport::SharedPtr
|
||||||
|
get_shared_dynamic_serialization_support();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport::ConstSharedPtr
|
||||||
|
get_shared_dynamic_serialization_support() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
size_t
|
||||||
|
get_item_count() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
get_member_id(size_t index) const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
get_member_id(const std::string & name) const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
get_array_index(size_t index) const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
get_array_index(const std::string & name) const;
|
||||||
|
|
||||||
|
|
||||||
|
// METHODS =======================================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage
|
||||||
|
clone(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
clone_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage
|
||||||
|
init_from_type(
|
||||||
|
DynamicMessageType & type, rcl_allocator_t allocator = rcl_get_default_allocator()) const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
init_from_type_shared(
|
||||||
|
DynamicMessageType & type, rcl_allocator_t allocator = rcl_get_default_allocator()) const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
equals(const DynamicMessage & other) const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
loan_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
loan_value(
|
||||||
|
const std::string & name,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
clear_all_values();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
clear_nonkey_values();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
clear_value(rosidl_dynamic_typesupport_member_id_t id);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
clear_value(const std::string & name);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
clear_sequence();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
insert_sequence_data();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
remove_sequence_data(rosidl_dynamic_typesupport_member_id_t index);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
serialize(rcl_serialized_message_t & buffer);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
deserialize(rcl_serialized_message_t & buffer);
|
||||||
|
|
||||||
|
|
||||||
|
// MEMBER ACCESS TEMPLATES =======================================================================
|
||||||
|
/**
|
||||||
|
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
|
||||||
|
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
|
||||||
|
*
|
||||||
|
* Explicitly:
|
||||||
|
* - Basic types: bool, byte, char
|
||||||
|
* - Float types: float, double
|
||||||
|
* - Int types: int8_t, int16_t, int32_t, int64_t
|
||||||
|
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
|
||||||
|
* - String types: std::string, std::u16string
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename ValueT>
|
||||||
|
ValueT
|
||||||
|
get_value(rosidl_dynamic_typesupport_member_id_t id);
|
||||||
|
|
||||||
|
template<typename ValueT>
|
||||||
|
ValueT
|
||||||
|
get_value(const std::string & name);
|
||||||
|
|
||||||
|
template<typename ValueT>
|
||||||
|
void
|
||||||
|
set_value(rosidl_dynamic_typesupport_member_id_t id, ValueT value);
|
||||||
|
|
||||||
|
template<typename ValueT>
|
||||||
|
void
|
||||||
|
set_value(const std::string & name, ValueT value);
|
||||||
|
|
||||||
|
template<typename ValueT>
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
insert_value(ValueT value);
|
||||||
|
|
||||||
|
|
||||||
|
// FIXED STRING MEMBER ACCESS ====================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_fixed_string_value(rosidl_dynamic_typesupport_member_id_t id, size_t string_length);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_fixed_string_value(const std::string & name, size_t string_length);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::u16string
|
||||||
|
get_fixed_wstring_value(rosidl_dynamic_typesupport_member_id_t id, size_t wstring_length);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::u16string
|
||||||
|
get_fixed_wstring_value(const std::string & name, size_t wstring_length);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_fixed_string_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_length);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_fixed_string_value(const std::string & name, const std::string value, size_t string_length);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_fixed_wstring_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_length);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_fixed_wstring_value(
|
||||||
|
const std::string & name, const std::u16string value, size_t wstring_length);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
insert_fixed_string_value(const std::string value, size_t string_length);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
insert_fixed_wstring_value(const std::u16string value, size_t wstring_length);
|
||||||
|
|
||||||
|
|
||||||
|
// BOUNDED STRING MEMBER ACCESS ==================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_bounded_string_value(rosidl_dynamic_typesupport_member_id_t id, size_t string_bound);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_bounded_string_value(const std::string & name, size_t string_bound);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::u16string
|
||||||
|
get_bounded_wstring_value(rosidl_dynamic_typesupport_member_id_t id, size_t wstring_bound);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::u16string
|
||||||
|
get_bounded_wstring_value(const std::string & name, size_t wstring_bound);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_bounded_string_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_bound);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_bounded_string_value(const std::string & name, const std::string value, size_t string_bound);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_bounded_wstring_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_bound);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_bounded_wstring_value(
|
||||||
|
const std::string & name, const std::u16string value, size_t wstring_bound);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
insert_bounded_string_value(const std::string value, size_t string_bound);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
insert_bounded_wstring_value(const std::u16string value, size_t wstring_bound);
|
||||||
|
|
||||||
|
|
||||||
|
// NESTED MEMBER ACCESS ==========================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage
|
||||||
|
get_complex_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage
|
||||||
|
get_complex_value(
|
||||||
|
const std::string & name,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
get_complex_value_shared(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
get_complex_value_shared(
|
||||||
|
const std::string & name,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_complex_value(rosidl_dynamic_typesupport_member_id_t id, DynamicMessage & value);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_complex_value(const std::string & name, DynamicMessage & value);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
insert_complex_value_copy(const DynamicMessage & value);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
insert_complex_value(DynamicMessage & value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// NOTE(methylDragon):
|
||||||
|
// This is just here to extend the lifetime of the serialization support
|
||||||
|
// It isn't actually used by the builder since the builder should compose its own support
|
||||||
|
//
|
||||||
|
// ... Though ideally it should be the exact same support as the one stored in the
|
||||||
|
// DynamicSerializationSupport
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data_;
|
||||||
|
bool is_loaned_;
|
||||||
|
|
||||||
|
// Used for returning the loaned value, and lifetime management
|
||||||
|
DynamicMessage::SharedPtr parent_data_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RCLCPP_DISABLE_COPY(DynamicMessage)
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
match_serialization_support_(
|
||||||
|
const DynamicSerializationSupport & serialization_support,
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_data_t & dynamic_data);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dynamic_typesupport
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
|
||||||
@@ -0,0 +1,197 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
|
||||||
|
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
|
||||||
|
|
||||||
|
#include <rcl/allocator.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace dynamic_typesupport
|
||||||
|
{
|
||||||
|
|
||||||
|
class DynamicMessage;
|
||||||
|
class DynamicMessageTypeBuilder;
|
||||||
|
|
||||||
|
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_t`
|
||||||
|
/**
|
||||||
|
* This class:
|
||||||
|
* - Exposes getter methods for the struct
|
||||||
|
* - Exposes the underlying serialization support API
|
||||||
|
*
|
||||||
|
* Ownership:
|
||||||
|
* - This class borrows the `rosidl_dynamic_typesupport_serialization_support_t` stored in the
|
||||||
|
* passed `DynamicSerializationSupport`.
|
||||||
|
* So it cannot outlive the `DynamicSerializationSupport`.
|
||||||
|
* - The `DynamicSerializationSupport`'s `rosidl_dynamic_typesupport_serialization_support_t`
|
||||||
|
* pointer must point to the same location in memory as the stored raw pointer!
|
||||||
|
*
|
||||||
|
* This class is meant to map to the lower level `rosidl_dynamic_typesupport_dynamic_type_t`,
|
||||||
|
* which can be constructed via `DynamicMessageTypeBuilder`, which maps to
|
||||||
|
* `rosidl_dynamic_typesupport_dynamic_type_builder_t`.
|
||||||
|
*
|
||||||
|
* The usual method of obtaining a `DynamicMessageType` is through construction of
|
||||||
|
* `rosidl_message_type_support_t` via `rcl_dynamic_message_type_support_handle_create()`, then
|
||||||
|
* taking ownership of its contents. But `DynamicMessageTypeBuilder` can also be used to obtain
|
||||||
|
* `DynamicMessageType` by constructing it bottom-up instead, since it exposes the lower_level
|
||||||
|
* rosidl methods.
|
||||||
|
*/
|
||||||
|
class DynamicMessageType : public std::enable_shared_from_this<DynamicMessageType>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageType)
|
||||||
|
|
||||||
|
// CONSTRUCTION ==================================================================================
|
||||||
|
// Most constructors require a passed in `DynamicSerializationSupport::SharedPtr`, to extend the
|
||||||
|
// lifetime of the serialization support (if the constructor cannot otherwise get it from args).
|
||||||
|
//
|
||||||
|
// In cases where a dynamic type pointer is passed, the serialization support composed by
|
||||||
|
// the type should be the exact same object managed by the `DynamicSerializationSupport`,
|
||||||
|
// otherwise the lifetime management will not work properly.
|
||||||
|
|
||||||
|
/// Construct a new `DynamicMessageType` with the provided dynamic type builder,
|
||||||
|
/// using its allocator
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
explicit DynamicMessageType(std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder);
|
||||||
|
|
||||||
|
/// Construct a new `DynamicMessageType` with the provided dynamic type builder and allocator
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType(
|
||||||
|
std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder,
|
||||||
|
rcl_allocator_t allocator);
|
||||||
|
|
||||||
|
/// Assume ownership of struct
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_t && rosidl_dynamic_type);
|
||||||
|
|
||||||
|
/// From description
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
/// Move constructor
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType(DynamicMessageType && other) noexcept;
|
||||||
|
|
||||||
|
/// Move assignment
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType & operator=(DynamicMessageType && other) noexcept;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual ~DynamicMessageType();
|
||||||
|
|
||||||
|
/// Swaps the serialization support if `serialization_support` is populated
|
||||||
|
/**
|
||||||
|
* The user can call this with another description to reconfigure the type without changing the
|
||||||
|
* serialization support
|
||||||
|
*/
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
init_from_description(
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator(),
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support = nullptr);
|
||||||
|
|
||||||
|
// GETTERS =======================================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_serialization_library_identifier() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_name() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
size_t
|
||||||
|
get_member_count() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_t &
|
||||||
|
get_rosidl_dynamic_type();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_type_t &
|
||||||
|
get_rosidl_dynamic_type() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport::SharedPtr
|
||||||
|
get_shared_dynamic_serialization_support();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport::ConstSharedPtr
|
||||||
|
get_shared_dynamic_serialization_support() const;
|
||||||
|
|
||||||
|
|
||||||
|
// METHODS =======================================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType
|
||||||
|
clone(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType::SharedPtr
|
||||||
|
clone_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
equals(const DynamicMessageType & other) const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage
|
||||||
|
build_dynamic_message(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
std::shared_ptr<DynamicMessage>
|
||||||
|
build_dynamic_message_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// NOTE(methylDragon):
|
||||||
|
// This is just here to extend the lifetime of the serialization support
|
||||||
|
// It isn't actually used by the builder since the builder should compose its own support
|
||||||
|
//
|
||||||
|
// ... Though ideally it should be the exact same support as the one stored in the
|
||||||
|
// `DynamicSerializationSupport`
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RCLCPP_DISABLE_COPY(DynamicMessageType)
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
match_serialization_support_(
|
||||||
|
const DynamicSerializationSupport & serialization_support,
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_type_t & rosidl_dynamic_type);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dynamic_typesupport
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
|
||||||
@@ -0,0 +1,409 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
|
||||||
|
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
|
||||||
|
|
||||||
|
#include <rcl/allocator.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace dynamic_typesupport
|
||||||
|
{
|
||||||
|
|
||||||
|
class DynamicMessage;
|
||||||
|
class DynamicMessageType;
|
||||||
|
|
||||||
|
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_builder_t *`
|
||||||
|
/**
|
||||||
|
* This class:
|
||||||
|
* - Manages the lifetime of the raw pointer.
|
||||||
|
* - Exposes getter methods to get the raw pointer and shared pointers
|
||||||
|
* - Exposes the underlying serialization support API
|
||||||
|
*
|
||||||
|
* Ownership:
|
||||||
|
* - This class borrows the rosidl_dynamic_typesupport_serialization_support_t stored in the passed
|
||||||
|
* `DynamicSerializationSupport`.
|
||||||
|
* So it cannot outlive the `DynamicSerializationSupport`.
|
||||||
|
* - The `DynamicSerializationSupport`'s `rosidl_dynamic_typesupport_serialization_support_t`
|
||||||
|
* pointer must point to the same location in memory as the stored raw pointer!
|
||||||
|
*
|
||||||
|
* This class is meant to map to rosidl_dynamic_typesupport_dynamic_type_builder_t, facilitating the
|
||||||
|
* construction of dynamic types bottom-up in the C++ layer.
|
||||||
|
*
|
||||||
|
* The usual method of obtaining a `DynamicMessageType` is through construction of
|
||||||
|
* `rosidl_message_type_support_t` via `rcl_dynamic_message_type_support_handle_create()`, then
|
||||||
|
* taking ownership of its contents.
|
||||||
|
* But `DynamicMessageTypeBuilder` can also be used to obtain `DynamicMessageType` by constructing
|
||||||
|
* it bottom-up instead, since it exposes the lower_level rosidl methods.
|
||||||
|
*/
|
||||||
|
class DynamicMessageTypeBuilder : public std::enable_shared_from_this<DynamicMessageTypeBuilder>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeBuilder)
|
||||||
|
|
||||||
|
// CONSTRUCTION ==================================================================================
|
||||||
|
// All constructors require a passed in `DynamicSerializationSupport::SharedPtr`, to extend the
|
||||||
|
// lifetime of the serialization support.
|
||||||
|
//
|
||||||
|
// In cases where a dynamic type builder pointer is passed, the serialization support composed by
|
||||||
|
// the builder should be the exact same object managed by the `DynamicSerializationSupport`,
|
||||||
|
// otherwise the lifetime management will not work properly.
|
||||||
|
|
||||||
|
/// Construct a new `DynamicMessageTypeBuilder` with the provided serialization support using its
|
||||||
|
/// allocator
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeBuilder(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const std::string & name);
|
||||||
|
|
||||||
|
/// Construct a new `DynamicMessageTypeBuilder` with the provided serialization support and
|
||||||
|
/// allocator
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeBuilder(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const std::string & name,
|
||||||
|
rcl_allocator_t allocator);
|
||||||
|
|
||||||
|
/// Assume ownership of struct
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeBuilder(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t && dynamic_type_builder);
|
||||||
|
|
||||||
|
/// From description
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeBuilder(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
/// Move constructor
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeBuilder(DynamicMessageTypeBuilder && other) noexcept;
|
||||||
|
|
||||||
|
/// Move assignment
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeBuilder & operator=(DynamicMessageTypeBuilder && other) noexcept;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual ~DynamicMessageTypeBuilder();
|
||||||
|
|
||||||
|
/// Swaps the serialization support if serialization_support is populated
|
||||||
|
/**
|
||||||
|
* The user can call this with another description to reconfigure the type without changing the
|
||||||
|
* serialization support
|
||||||
|
*/
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
init_from_description(
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator(),
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support = nullptr);
|
||||||
|
|
||||||
|
|
||||||
|
// GETTERS =======================================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_serialization_library_identifier() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_name() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t &
|
||||||
|
get_rosidl_dynamic_type_builder();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_type_builder_t &
|
||||||
|
get_rosidl_dynamic_type_builder() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport::SharedPtr
|
||||||
|
get_shared_dynamic_serialization_support();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport::ConstSharedPtr
|
||||||
|
get_shared_dynamic_serialization_support() const;
|
||||||
|
|
||||||
|
|
||||||
|
// METHODS =======================================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_name(const std::string & name);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeBuilder
|
||||||
|
clone(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeBuilder::SharedPtr
|
||||||
|
clone_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
clear(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage
|
||||||
|
build_dynamic_message(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
build_dynamic_message_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType
|
||||||
|
build_dynamic_message_type(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType::SharedPtr
|
||||||
|
build_dynamic_message_type_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
|
||||||
|
// ADD MEMBERS TEMPLATES =========================================================================
|
||||||
|
/**
|
||||||
|
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
|
||||||
|
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
|
||||||
|
*
|
||||||
|
* Explicitly:
|
||||||
|
* - Basic types: bool, byte, char
|
||||||
|
* - Float types: float, double
|
||||||
|
* - Int types: int8_t, int16_t, int32_t, int64_t
|
||||||
|
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
|
||||||
|
* - String types: std::string, std::u16string
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename MemberT>
|
||||||
|
void
|
||||||
|
add_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
template<typename MemberT>
|
||||||
|
void
|
||||||
|
add_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t array_length,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
template<typename MemberT>
|
||||||
|
void
|
||||||
|
add_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
template<typename MemberT>
|
||||||
|
void
|
||||||
|
add_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t sequence_bound,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
|
||||||
|
// ADD FIXED STRING MEMBERS ======================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_fixed_string_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_fixed_wstring_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_fixed_string_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t string_length, size_t array_length, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_fixed_wstring_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t wstring_length, size_t array_length, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_fixed_string_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_fixed_wstring_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_fixed_string_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t string_length, size_t sequence_bound, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_fixed_wstring_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t wstring_length, size_t sequence_bound, const std::string & default_value = "");
|
||||||
|
|
||||||
|
|
||||||
|
// ADD BOUNDED STRING MEMBERS ====================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_bounded_string_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_bounded_wstring_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_bounded_string_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t string_bound, size_t array_length, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_bounded_wstring_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t wstring_bound, size_t array_length, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_bounded_string_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_bounded_wstring_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_bounded_string_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t string_bound, size_t sequence_bound, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_bounded_wstring_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t wstring_bound, size_t sequence_bound, const std::string & default_value = "");
|
||||||
|
|
||||||
|
|
||||||
|
// ADD NESTED MEMBERS ============================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_complex_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageType & nested_type, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_complex_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageType & nested_type, size_t array_length, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_complex_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageType & nested_type, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_complex_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageType & nested_type, size_t sequence_bound,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_complex_member_builder(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_complex_array_member_builder(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageTypeBuilder & nested_type_builder, size_t array_length,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_complex_unbounded_sequence_member_builder(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value = "");
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_complex_bounded_sequence_member_builder(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageTypeBuilder & nested_type_builder, size_t sequence_bound,
|
||||||
|
const std::string & default_value = "");
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// NOTE(methylDragon):
|
||||||
|
// This is just here to extend the lifetime of the serialization support
|
||||||
|
// It isn't actually used by the builder since the builder should compose its own support
|
||||||
|
//
|
||||||
|
// ... Though ideally it should be the exact same support as the one stored in the
|
||||||
|
// `DynamicSerializationSupport`
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RCLCPP_DISABLE_COPY(DynamicMessageTypeBuilder)
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeBuilder();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
init_from_serialization_support_(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const std::string & name,
|
||||||
|
rcl_allocator_t allocator);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
match_serialization_support_(
|
||||||
|
const DynamicSerializationSupport & serialization_support,
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_type_builder_t & dynamic_type_builder);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dynamic_typesupport
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
|
||||||
|
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
|
||||||
|
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
|
||||||
|
|
||||||
|
#include <rcl/allocator.h>
|
||||||
|
|
||||||
|
#include <rosidl_dynamic_typesupport/dynamic_message_type_support_struct.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
#include <rosidl_runtime_c/message_type_support_struct.h>
|
||||||
|
#include <rosidl_runtime_c/type_description/type_description__struct.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
|
|
||||||
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace dynamic_typesupport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Utility wrapper class for `rosidl_message_type_support_t` containing managed
|
||||||
|
/// instances of the typesupport handle impl.
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* NOTE: This class is the recommended way to obtain the dynamic message type
|
||||||
|
* support struct, instead of `rcl_dynamic_message_type_support_handle_init()`,
|
||||||
|
* because this class will manage the lifetimes for you.
|
||||||
|
*
|
||||||
|
* Do NOT call rcl_dynamic_message_type_support_handle_fini
|
||||||
|
*
|
||||||
|
* This class:
|
||||||
|
* - Exposes getter methods for the struct
|
||||||
|
* - Stores shared pointers to wrapper classes that expose the underlying
|
||||||
|
* serialization support API
|
||||||
|
*
|
||||||
|
* Ownership:
|
||||||
|
* - This class, similarly to the `rosidl_dynamic_typesupport_serialization_support_t`, must outlive
|
||||||
|
* all downstream usages of the serialization support.
|
||||||
|
*/
|
||||||
|
class DynamicMessageTypeSupport : public std::enable_shared_from_this<DynamicMessageTypeSupport>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeSupport)
|
||||||
|
|
||||||
|
// CONSTRUCTION ==================================================================================
|
||||||
|
/// From description
|
||||||
|
/// Does NOT take ownership of the description (copies instead.)
|
||||||
|
/// Constructs type support top-down (calling `rcl_dynamic_message_type_support_handle_create()`)
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeSupport(
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
const std::string & serialization_library_name = "",
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
/// From description, for provided serialization support
|
||||||
|
/// Does NOT take ownership of the description (copies instead.)
|
||||||
|
/// Constructs type support top-down (calling `rosidl_dynamic_message_type_support_handle_init()`)
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeSupport(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
/// Assume ownership of managed types
|
||||||
|
/// Does NOT take ownership of the description (copies instead.)
|
||||||
|
///
|
||||||
|
/// The serialization support used to construct all managed SharedPtrs must match.
|
||||||
|
/// The structure of the provided `description` must match the `dynamic_message_type`
|
||||||
|
/// The structure of the provided `dynamic_message_type` must match the `dynamic_message
|
||||||
|
///
|
||||||
|
/// In this case, the user would have constructed the type support bototm-up (by creating the
|
||||||
|
/// respective dynamic members.)
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeSupport(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
DynamicMessageType::SharedPtr dynamic_message_type,
|
||||||
|
DynamicMessage::SharedPtr dynamic_message,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual ~DynamicMessageTypeSupport();
|
||||||
|
|
||||||
|
|
||||||
|
// GETTERS =======================================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_serialization_library_identifier() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const rosidl_message_type_support_t &
|
||||||
|
get_const_rosidl_message_type_support();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const rosidl_message_type_support_t &
|
||||||
|
get_const_rosidl_message_type_support() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription &
|
||||||
|
get_rosidl_runtime_c_type_description() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport::SharedPtr
|
||||||
|
get_shared_dynamic_serialization_support();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport::ConstSharedPtr
|
||||||
|
get_shared_dynamic_serialization_support() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType::SharedPtr
|
||||||
|
get_shared_dynamic_message_type();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageType::ConstSharedPtr
|
||||||
|
get_shared_dynamic_message_type() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
get_shared_dynamic_message();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessage::ConstSharedPtr
|
||||||
|
get_shared_dynamic_message() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RCLCPP_DISABLE_COPY(DynamicMessageTypeSupport)
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_message_type_support_t &
|
||||||
|
get_rosidl_message_type_support();
|
||||||
|
|
||||||
|
private:
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicMessageTypeSupport();
|
||||||
|
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||||
|
DynamicMessageType::SharedPtr dynamic_message_type_;
|
||||||
|
DynamicMessage::SharedPtr dynamic_message_;
|
||||||
|
|
||||||
|
rosidl_message_type_support_t rosidl_message_type_support_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dynamic_typesupport
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
|
||||||
|
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
|
||||||
|
|
||||||
|
#include <rcl/allocator.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/serialization_support.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace dynamic_typesupport
|
||||||
|
{
|
||||||
|
|
||||||
|
/// Utility wrapper class for rosidl_dynamic_typesupport_serialization_support_t
|
||||||
|
/**
|
||||||
|
* This class:
|
||||||
|
* - Exposes getter methods for the struct
|
||||||
|
* - Exposes the underlying serialization support API
|
||||||
|
*
|
||||||
|
* Ownership:
|
||||||
|
* - This class, similarly to the rosidl_dynamic_typesupport_serialization_support_t, must outlive
|
||||||
|
* all downstream usages of the serialization support.
|
||||||
|
*/
|
||||||
|
class DynamicSerializationSupport : public std::enable_shared_from_this<DynamicSerializationSupport>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicSerializationSupport)
|
||||||
|
|
||||||
|
// CONSTRUCTION ==================================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
explicit DynamicSerializationSupport(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
/// Get the rmw middleware implementation specific serialization support (configured by name)
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport(
|
||||||
|
const std::string & serialization_library_name,
|
||||||
|
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||||
|
|
||||||
|
/// Assume ownership of struct
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
explicit DynamicSerializationSupport(
|
||||||
|
rosidl_dynamic_typesupport_serialization_support_t && rosidl_serialization_support);
|
||||||
|
|
||||||
|
/// Move constructor
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport(DynamicSerializationSupport && other) noexcept;
|
||||||
|
|
||||||
|
/// Move assignment
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
DynamicSerializationSupport & operator=(DynamicSerializationSupport && other) noexcept;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual ~DynamicSerializationSupport();
|
||||||
|
|
||||||
|
|
||||||
|
// GETTERS =======================================================================================
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const std::string
|
||||||
|
get_serialization_library_identifier() const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rosidl_dynamic_typesupport_serialization_support_t &
|
||||||
|
get_rosidl_serialization_support();
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const rosidl_dynamic_typesupport_serialization_support_t &
|
||||||
|
get_rosidl_serialization_support() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RCLCPP_DISABLE_COPY(DynamicSerializationSupport)
|
||||||
|
|
||||||
|
private:
|
||||||
|
rosidl_dynamic_typesupport_serialization_support_t rosidl_serialization_support_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace dynamic_typesupport
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
|
||||||
311
rclcpp/include/rclcpp/event_handler.hpp
Normal file
311
rclcpp/include/rclcpp/event_handler.hpp
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__EVENT_HANDLER_HPP_
|
||||||
|
#define RCLCPP__EVENT_HANDLER_HPP_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rcl/error_handling.h"
|
||||||
|
#include "rcl/event_callback.h"
|
||||||
|
#include "rmw/impl/cpp/demangle.hpp"
|
||||||
|
#include "rmw/incompatible_qos_events_statuses.h"
|
||||||
|
#include "rmw/events_statuses/incompatible_type.h"
|
||||||
|
|
||||||
|
#include "rcutils/logging_macros.h"
|
||||||
|
|
||||||
|
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
#include "rclcpp/function_traits.hpp"
|
||||||
|
#include "rclcpp/logging.hpp"
|
||||||
|
#include "rclcpp/waitable.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
|
||||||
|
using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
|
||||||
|
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
|
||||||
|
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
|
||||||
|
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
|
||||||
|
using QOSMessageLostInfo = rmw_message_lost_status_t;
|
||||||
|
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
|
||||||
|
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
|
||||||
|
|
||||||
|
using IncompatibleTypeInfo = rmw_incompatible_type_status_t;
|
||||||
|
using MatchedInfo = rmw_matched_status_t;
|
||||||
|
|
||||||
|
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
|
||||||
|
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
|
||||||
|
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
|
||||||
|
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
|
||||||
|
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
|
||||||
|
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
|
||||||
|
using QOSRequestedIncompatibleQoSCallbackType =
|
||||||
|
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
|
||||||
|
|
||||||
|
using IncompatibleTypeCallbackType = std::function<void (IncompatibleTypeInfo &)>;
|
||||||
|
using PublisherMatchedCallbackType = std::function<void (MatchedInfo &)>;
|
||||||
|
using SubscriptionMatchedCallbackType = std::function<void (MatchedInfo &)>;
|
||||||
|
|
||||||
|
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
|
||||||
|
struct PublisherEventCallbacks
|
||||||
|
{
|
||||||
|
QOSDeadlineOfferedCallbackType deadline_callback;
|
||||||
|
QOSLivelinessLostCallbackType liveliness_callback;
|
||||||
|
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
|
||||||
|
IncompatibleTypeCallbackType incompatible_type_callback;
|
||||||
|
PublisherMatchedCallbackType matched_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
|
||||||
|
struct SubscriptionEventCallbacks
|
||||||
|
{
|
||||||
|
QOSDeadlineRequestedCallbackType deadline_callback;
|
||||||
|
QOSLivelinessChangedCallbackType liveliness_callback;
|
||||||
|
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
|
||||||
|
QOSMessageLostCallbackType message_lost_callback;
|
||||||
|
IncompatibleTypeCallbackType incompatible_type_callback;
|
||||||
|
SubscriptionMatchedCallbackType matched_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
UnsupportedEventTypeException(
|
||||||
|
rcl_ret_t ret,
|
||||||
|
const rcl_error_state_t * error_state,
|
||||||
|
const std::string & prefix);
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
UnsupportedEventTypeException(
|
||||||
|
const exceptions::RCLErrorBase & base_exc,
|
||||||
|
const std::string & prefix);
|
||||||
|
};
|
||||||
|
|
||||||
|
class EventHandlerBase : public Waitable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class EntityType : std::size_t
|
||||||
|
{
|
||||||
|
Event,
|
||||||
|
};
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual ~EventHandlerBase();
|
||||||
|
|
||||||
|
/// Get the number of ready events
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
size_t
|
||||||
|
get_number_of_ready_events() override;
|
||||||
|
|
||||||
|
/// Add the Waitable to a wait set.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
add_to_wait_set(rcl_wait_set_t * wait_set) override;
|
||||||
|
|
||||||
|
/// Check if the Waitable is ready.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
is_ready(rcl_wait_set_t * wait_set) override;
|
||||||
|
|
||||||
|
/// Set a callback to be called when each new event instance occurs.
|
||||||
|
/**
|
||||||
|
* The callback receives a size_t which is the number of events that occurred
|
||||||
|
* since the last time this callback was called.
|
||||||
|
* Normally this is 1, but can be > 1 if events occurred before any
|
||||||
|
* callback was set.
|
||||||
|
*
|
||||||
|
* The callback also receives an int identifier argument.
|
||||||
|
* This is needed because a Waitable may be composed of several distinct entities,
|
||||||
|
* such as subscriptions, services, etc.
|
||||||
|
* The application should provide a generic callback function that will be then
|
||||||
|
* forwarded by the waitable to all of its entities.
|
||||||
|
* Before forwarding, a different value for the identifier argument will be
|
||||||
|
* bond to the function.
|
||||||
|
* This implies that the provided callback can use the identifier to behave
|
||||||
|
* differently depending on which entity triggered the waitable to become ready.
|
||||||
|
*
|
||||||
|
* Since this callback is called from the middleware, you should aim to make
|
||||||
|
* it fast and not blocking.
|
||||||
|
* If you need to do a lot of work or wait for some other event, you should
|
||||||
|
* spin it off to another thread, otherwise you risk blocking the middleware.
|
||||||
|
*
|
||||||
|
* Calling it again will clear any previously set callback.
|
||||||
|
*
|
||||||
|
* An exception will be thrown if the callback is not callable.
|
||||||
|
*
|
||||||
|
* This function is thread-safe.
|
||||||
|
*
|
||||||
|
* If you want more information available in the callback, like the qos event
|
||||||
|
* or other information, you may use a lambda with captures or std::bind.
|
||||||
|
*
|
||||||
|
* \sa rmw_event_set_callback
|
||||||
|
* \sa rcl_event_set_callback
|
||||||
|
*
|
||||||
|
* \param[in] callback functor to be called when a new event occurs
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
set_on_ready_callback(std::function<void(size_t, int)> callback) override
|
||||||
|
{
|
||||||
|
if (!callback) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"The callback passed to set_on_ready_callback "
|
||||||
|
"is not callable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: we bind the int identifier argument to this waitable's entity types
|
||||||
|
auto new_callback =
|
||||||
|
[callback, this](size_t number_of_events) {
|
||||||
|
try {
|
||||||
|
callback(number_of_events, static_cast<int>(EntityType::Event));
|
||||||
|
} catch (const std::exception & exception) {
|
||||||
|
RCLCPP_ERROR_STREAM(
|
||||||
|
// TODO(wjwwood): get this class access to the node logger it is associated with
|
||||||
|
rclcpp::get_logger("rclcpp"),
|
||||||
|
"rclcpp::EventHandlerBase@" << this <<
|
||||||
|
" caught " << rmw::impl::cpp::demangle(exception) <<
|
||||||
|
" exception in user-provided callback for the 'on ready' callback: " <<
|
||||||
|
exception.what());
|
||||||
|
} catch (...) {
|
||||||
|
RCLCPP_ERROR_STREAM(
|
||||||
|
rclcpp::get_logger("rclcpp"),
|
||||||
|
"rclcpp::EventHandlerBase@" << this <<
|
||||||
|
" caught unhandled exception in user-provided callback " <<
|
||||||
|
"for the 'on ready' callback");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||||
|
|
||||||
|
// Set it temporarily to the new callback, while we replace the old one.
|
||||||
|
// This two-step setting, prevents a gap where the old std::function has
|
||||||
|
// been replaced but the middleware hasn't been told about the new one yet.
|
||||||
|
set_on_new_event_callback(
|
||||||
|
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||||
|
static_cast<const void *>(&new_callback));
|
||||||
|
|
||||||
|
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||||
|
on_new_event_callback_ = new_callback;
|
||||||
|
|
||||||
|
// Set it again, now using the permanent storage.
|
||||||
|
set_on_new_event_callback(
|
||||||
|
rclcpp::detail::cpp_callback_trampoline<
|
||||||
|
decltype(on_new_event_callback_), const void *, size_t>,
|
||||||
|
static_cast<const void *>(&on_new_event_callback_));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unset the callback registered for new events, if any.
|
||||||
|
void
|
||||||
|
clear_on_ready_callback() override
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||||
|
if (on_new_event_callback_) {
|
||||||
|
set_on_new_event_callback(nullptr, nullptr);
|
||||||
|
on_new_event_callback_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
|
||||||
|
|
||||||
|
std::recursive_mutex callback_mutex_;
|
||||||
|
std::function<void(size_t)> on_new_event_callback_{nullptr};
|
||||||
|
|
||||||
|
rcl_event_t event_handle_;
|
||||||
|
size_t wait_set_event_index_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using QOSEventHandlerBase [[deprecated("Use rclcpp::EventHandlerBase")]] = EventHandlerBase;
|
||||||
|
|
||||||
|
template<typename EventCallbackT, typename ParentHandleT>
|
||||||
|
class EventHandler : public EventHandlerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename InitFuncT, typename EventTypeEnum>
|
||||||
|
EventHandler(
|
||||||
|
const EventCallbackT & callback,
|
||||||
|
InitFuncT init_func,
|
||||||
|
ParentHandleT parent_handle,
|
||||||
|
EventTypeEnum event_type)
|
||||||
|
: parent_handle_(parent_handle), event_callback_(callback)
|
||||||
|
{
|
||||||
|
event_handle_ = rcl_get_zero_initialized_event();
|
||||||
|
rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
if (ret == RCL_RET_UNSUPPORTED) {
|
||||||
|
UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
|
||||||
|
rcl_reset_error();
|
||||||
|
throw exc;
|
||||||
|
} else {
|
||||||
|
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take data so that the callback cannot be scheduled again
|
||||||
|
std::shared_ptr<void>
|
||||||
|
take_data() override
|
||||||
|
{
|
||||||
|
EventCallbackInfoT callback_info;
|
||||||
|
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
RCUTILS_LOG_ERROR_NAMED(
|
||||||
|
"rclcpp",
|
||||||
|
"Couldn't take event info: %s", rcl_get_error_string().str);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<void>
|
||||||
|
take_data_by_entity_id(size_t id) override
|
||||||
|
{
|
||||||
|
(void)id;
|
||||||
|
return take_data();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute any entities of the Waitable that are ready.
|
||||||
|
void
|
||||||
|
execute(std::shared_ptr<void> & data) override
|
||||||
|
{
|
||||||
|
if (!data) {
|
||||||
|
throw std::runtime_error("'data' is empty");
|
||||||
|
}
|
||||||
|
auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
|
||||||
|
event_callback_(*callback_ptr);
|
||||||
|
callback_ptr.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
using EventCallbackInfoT = typename std::remove_reference<typename
|
||||||
|
rclcpp::function_traits::function_traits<EventCallbackT>::template argument_type<0>>::type;
|
||||||
|
|
||||||
|
ParentHandleT parent_handle_;
|
||||||
|
EventCallbackT event_callback_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename EventCallbackT, typename ParentHandleT>
|
||||||
|
using QOSEventHandler [[deprecated("Use rclcpp::EventHandler")]] = EventHandler<EventCallbackT,
|
||||||
|
ParentHandleT>;
|
||||||
|
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__EVENT_HANDLER_HPP_
|
||||||
@@ -315,6 +315,16 @@ public:
|
|||||||
virtual void
|
virtual void
|
||||||
spin_all(std::chrono::nanoseconds max_duration);
|
spin_all(std::chrono::nanoseconds max_duration);
|
||||||
|
|
||||||
|
|
||||||
|
/// Collect work once and execute the next available work, optionally within a duration.
|
||||||
|
/**
|
||||||
|
* This function can be overridden. The default implementation is suitable for
|
||||||
|
* a single-thread model of execution.
|
||||||
|
* Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
|
||||||
|
* to block (which may have unintended consequences).
|
||||||
|
* \param[in] timeout The maximum amount of time to spend waiting for work.
|
||||||
|
* `-1` is potentially block forever waiting for work.
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
virtual void
|
virtual void
|
||||||
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
||||||
@@ -413,12 +423,29 @@ public:
|
|||||||
is_spinning();
|
is_spinning();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
/// Add a node to executor, execute the next available unit of work, and remove the node.
|
||||||
|
/**
|
||||||
|
* Implementation of spin_node_once using std::chrono::nanoseconds
|
||||||
|
* \param[in] node Shared pointer to the node to add.
|
||||||
|
* \param[in] timeout How long to wait for work to become available. Negative values cause
|
||||||
|
* spin_node_once to block indefinitely (the default behavior). A timeout of 0 causes this
|
||||||
|
* function to be non-blocking.
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
void
|
void
|
||||||
spin_node_once_nanoseconds(
|
spin_node_once_nanoseconds(
|
||||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
|
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
|
||||||
std::chrono::nanoseconds timeout);
|
std::chrono::nanoseconds timeout);
|
||||||
|
|
||||||
|
/// Collect work and execute available work, optionally within a duration.
|
||||||
|
/**
|
||||||
|
* Implementation of spin_some and spin_all.
|
||||||
|
* The exhaustive flag controls if the function will re-collect available work within the duration.
|
||||||
|
*
|
||||||
|
* \param[in] max_duration The maximum amount of time to spend executing work, or 0 for no limit.
|
||||||
|
* \param[in] exhaustive when set to true, continue to collect work and execute (spin_all)
|
||||||
|
* when set to false, return when all collected work is executed (spin_some)
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
void
|
void
|
||||||
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
|
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
|
||||||
@@ -433,30 +460,60 @@ protected:
|
|||||||
void
|
void
|
||||||
execute_any_executable(AnyExecutable & any_exec);
|
execute_any_executable(AnyExecutable & any_exec);
|
||||||
|
|
||||||
|
/// Run subscription executable.
|
||||||
|
/**
|
||||||
|
* Do necessary setup and tear-down as well as executing the subscription.
|
||||||
|
* \param[in] subscription Subscription to execute
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
static void
|
static void
|
||||||
execute_subscription(
|
execute_subscription(
|
||||||
rclcpp::SubscriptionBase::SharedPtr subscription);
|
rclcpp::SubscriptionBase::SharedPtr subscription);
|
||||||
|
|
||||||
|
/// Run timer executable.
|
||||||
|
/**
|
||||||
|
* Do necessary setup and tear-down as well as executing the timer callback.
|
||||||
|
* \param[in] timer Timer to execute
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
static void
|
static void
|
||||||
execute_timer(rclcpp::TimerBase::SharedPtr timer);
|
execute_timer(rclcpp::TimerBase::SharedPtr timer);
|
||||||
|
|
||||||
|
/// Run service server executable.
|
||||||
|
/**
|
||||||
|
* Do necessary setup and tear-down as well as executing the service server callback.
|
||||||
|
* \param[in] service Service to execute
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
static void
|
static void
|
||||||
execute_service(rclcpp::ServiceBase::SharedPtr service);
|
execute_service(rclcpp::ServiceBase::SharedPtr service);
|
||||||
|
|
||||||
|
/// Run service client executable.
|
||||||
|
/**
|
||||||
|
* Do necessary setup and tear-down as well as executing the service client callback.
|
||||||
|
* \param[in] service Service to execute
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
static void
|
static void
|
||||||
execute_client(rclcpp::ClientBase::SharedPtr client);
|
execute_client(rclcpp::ClientBase::SharedPtr client);
|
||||||
|
|
||||||
|
/// Block until more work becomes avilable or timeout is reached.
|
||||||
/**
|
/**
|
||||||
|
* Builds a set of waitable entities, which are passed to the middleware.
|
||||||
|
* After building wait set, waits on middleware to notify.
|
||||||
|
* \param[in] timeout duration to wait for new work to become available.
|
||||||
* \throws std::runtime_error if the wait set can be cleared
|
* \throws std::runtime_error if the wait set can be cleared
|
||||||
*/
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
void
|
void
|
||||||
wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
||||||
|
|
||||||
|
/// Find node associated with a callback group
|
||||||
|
/**
|
||||||
|
* \param[in] weak_groups_to_nodes map of callback groups to nodes
|
||||||
|
* \param[in] group callback group to find assocatiated node
|
||||||
|
* \return Pointer to associated node if found, else nullptr
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||||
get_node_by_group(
|
get_node_by_group(
|
||||||
@@ -475,6 +532,11 @@ protected:
|
|||||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
|
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
|
||||||
|
|
||||||
|
/// Find the callback group associated with a timer
|
||||||
|
/**
|
||||||
|
* \param[in] timer Timer to find associated callback group
|
||||||
|
* \return Pointer to callback group node if found, else nullptr
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
rclcpp::CallbackGroup::SharedPtr
|
rclcpp::CallbackGroup::SharedPtr
|
||||||
get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
|
get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
|
||||||
@@ -502,16 +564,54 @@ protected:
|
|||||||
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
|
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
|
||||||
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
|
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
|
||||||
|
|
||||||
|
/// Check for executable in ready state and populate union structure.
|
||||||
|
/**
|
||||||
|
* \param[out] any_executable populated union structure of ready executable
|
||||||
|
* \return true if an executable was ready and any_executable was populated,
|
||||||
|
* otherwise false
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
bool
|
bool
|
||||||
get_next_ready_executable(AnyExecutable & any_executable);
|
get_next_ready_executable(AnyExecutable & any_executable);
|
||||||
|
|
||||||
|
/// Check for executable in ready state and populate union structure.
|
||||||
|
/**
|
||||||
|
* This is the implementation of get_next_ready_executable that takes into
|
||||||
|
* account the current state of callback groups' association with nodes and
|
||||||
|
* executors.
|
||||||
|
*
|
||||||
|
* This checks in a particular order for available work:
|
||||||
|
* * Timers
|
||||||
|
* * Subscriptions
|
||||||
|
* * Services
|
||||||
|
* * Clients
|
||||||
|
* * Waitable
|
||||||
|
*
|
||||||
|
* If the next executable is not associated with this executor/node pair,
|
||||||
|
* then this method will return false.
|
||||||
|
*
|
||||||
|
* \param[out] any_executable populated union structure of ready executable
|
||||||
|
* \param[in] weak_groups_to_nodes mapping of callback groups to nodes
|
||||||
|
* \return true if an executable was ready and any_executable was populated,
|
||||||
|
* otherwise false
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
bool
|
bool
|
||||||
get_next_ready_executable_from_map(
|
get_next_ready_executable_from_map(
|
||||||
AnyExecutable & any_executable,
|
AnyExecutable & any_executable,
|
||||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||||
|
|
||||||
|
/// Wait for executable in ready state and populate union structure.
|
||||||
|
/**
|
||||||
|
* If an executable is ready, it will return immediately, otherwise
|
||||||
|
* block based on the timeout for work to become ready.
|
||||||
|
*
|
||||||
|
* \param[out] any_executable populated union structure of ready executable
|
||||||
|
* \param[in] timeout duration of time to wait for work, a negative value
|
||||||
|
* (the defualt behavior), will make this function block indefinitely
|
||||||
|
* \return true if an executable was ready and any_executable was populated,
|
||||||
|
* otherwise false
|
||||||
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
bool
|
bool
|
||||||
get_next_executable(
|
get_next_executable(
|
||||||
@@ -565,10 +665,19 @@ protected:
|
|||||||
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>
|
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>
|
||||||
WeakNodesToGuardConditionsMap;
|
WeakNodesToGuardConditionsMap;
|
||||||
|
|
||||||
|
typedef std::map<rclcpp::CallbackGroup::WeakPtr,
|
||||||
|
const rclcpp::GuardCondition *,
|
||||||
|
std::owner_less<rclcpp::CallbackGroup::WeakPtr>>
|
||||||
|
WeakCallbackGroupsToGuardConditionsMap;
|
||||||
|
|
||||||
/// maps nodes to guard conditions
|
/// maps nodes to guard conditions
|
||||||
WeakNodesToGuardConditionsMap
|
WeakNodesToGuardConditionsMap
|
||||||
weak_nodes_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
weak_nodes_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||||
|
|
||||||
|
/// maps callback groups to guard conditions
|
||||||
|
WeakCallbackGroupsToGuardConditionsMap
|
||||||
|
weak_groups_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||||
|
|
||||||
/// maps callback groups associated to nodes
|
/// maps callback groups associated to nodes
|
||||||
WeakCallbackGroupsToNodesMap
|
WeakCallbackGroupsToNodesMap
|
||||||
weak_groups_associated_with_executor_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
weak_groups_associated_with_executor_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ public:
|
|||||||
*
|
*
|
||||||
* \param options common options for all executors
|
* \param options common options for all executors
|
||||||
* \param number_of_threads number of threads to have in the thread pool,
|
* \param number_of_threads number of threads to have in the thread pool,
|
||||||
* the default 0 will use the number of cpu cores found instead
|
* the default 0 will use the number of cpu cores found (minimum of 2)
|
||||||
* \param yield_before_execute if true std::this_thread::yield() is called
|
* \param yield_before_execute if true std::this_thread::yield() is called
|
||||||
* \param timeout maximum time to wait
|
* \param timeout maximum time to wait
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -86,8 +86,7 @@ public:
|
|||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
|
||||||
if (!has_data_()) {
|
if (!has_data_()) {
|
||||||
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Calling dequeue on empty intra-process buffer");
|
return BufferT();
|
||||||
throw std::runtime_error("Calling dequeue on empty intra-process buffer");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto request = std::move(ring_buffer_[read_index_]);
|
auto request = std::move(ring_buffer_[read_index_]);
|
||||||
|
|||||||
@@ -454,6 +454,8 @@ private:
|
|||||||
if (std::next(it) == subscription_ids.end()) {
|
if (std::next(it) == subscription_ids.end()) {
|
||||||
// If this is the last subscription, give up ownership
|
// If this is the last subscription, give up ownership
|
||||||
subscription->provide_intra_process_data(std::move(message));
|
subscription->provide_intra_process_data(std::move(message));
|
||||||
|
// Last message delivered, break from for loop
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
// Copy the message since we have additional subscriptions to serve
|
// Copy the message since we have additional subscriptions to serve
|
||||||
Deleter deleter = message.get_deleter();
|
Deleter deleter = message.get_deleter();
|
||||||
@@ -493,6 +495,8 @@ private:
|
|||||||
if (std::next(it) == subscription_ids.end()) {
|
if (std::next(it) == subscription_ids.end()) {
|
||||||
// If this is the last subscription, give up ownership
|
// If this is the last subscription, give up ownership
|
||||||
ros_message_subscription->provide_intra_process_message(std::move(message));
|
ros_message_subscription->provide_intra_process_message(std::move(message));
|
||||||
|
// Last message delivered, break from for loop
|
||||||
|
break;
|
||||||
} else {
|
} else {
|
||||||
// Copy the message since we have additional subscriptions to serve
|
// Copy the message since we have additional subscriptions to serve
|
||||||
Deleter deleter = message.get_deleter();
|
Deleter deleter = message.get_deleter();
|
||||||
|
|||||||
@@ -109,8 +109,14 @@ public:
|
|||||||
|
|
||||||
if (any_callback_.use_take_shared_method()) {
|
if (any_callback_.use_take_shared_method()) {
|
||||||
shared_msg = this->buffer_->consume_shared();
|
shared_msg = this->buffer_->consume_shared();
|
||||||
|
if (!shared_msg) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
unique_msg = this->buffer_->consume_unique();
|
unique_msg = this->buffer_->consume_unique();
|
||||||
|
if (!unique_msg) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return std::static_pointer_cast<void>(
|
return std::static_pointer_cast<void>(
|
||||||
std::make_shared<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
|
std::make_shared<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
|
||||||
@@ -138,7 +144,7 @@ protected:
|
|||||||
execute_impl(std::shared_ptr<void> & data)
|
execute_impl(std::shared_ptr<void> & data)
|
||||||
{
|
{
|
||||||
if (!data) {
|
if (!data) {
|
||||||
throw std::runtime_error("'data' is empty");
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rmw_message_info_t msg_info;
|
rmw_message_info_t msg_info;
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
{}
|
{}
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
virtual ~SubscriptionIntraProcessBase();
|
virtual ~SubscriptionIntraProcessBase() = default;
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
size_t
|
size_t
|
||||||
|
|||||||
@@ -78,38 +78,12 @@ public:
|
|||||||
node_base,
|
node_base,
|
||||||
topic_name,
|
topic_name,
|
||||||
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||||
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos)),
|
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos),
|
||||||
|
// NOTE(methylDragon): Passing these args separately is necessary for event binding
|
||||||
|
options.event_callbacks,
|
||||||
|
options.use_default_callbacks),
|
||||||
ts_lib_(ts_lib)
|
ts_lib_(ts_lib)
|
||||||
{
|
{}
|
||||||
// This is unfortunately duplicated with the code in publisher.hpp.
|
|
||||||
// TODO(nnmm): Deduplicate by moving this into PublisherBase.
|
|
||||||
if (options.event_callbacks.deadline_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options.event_callbacks.deadline_callback,
|
|
||||||
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
|
|
||||||
}
|
|
||||||
if (options.event_callbacks.liveliness_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options.event_callbacks.liveliness_callback,
|
|
||||||
RCL_PUBLISHER_LIVELINESS_LOST);
|
|
||||||
}
|
|
||||||
if (options.event_callbacks.incompatible_qos_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options.event_callbacks.incompatible_qos_callback,
|
|
||||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
|
||||||
} else if (options.use_default_callbacks) {
|
|
||||||
// Register default callback when not specified
|
|
||||||
try {
|
|
||||||
this->add_event_handler(
|
|
||||||
[this](QOSOfferedIncompatibleQoSInfo & info) {
|
|
||||||
this->default_incompatible_qos_callback(info);
|
|
||||||
},
|
|
||||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
|
||||||
} catch (UnsupportedEventTypeException & /*exc*/) {
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
virtual ~GenericPublisher() = default;
|
virtual ~GenericPublisher() = default;
|
||||||
|
|||||||
@@ -81,45 +81,13 @@ public:
|
|||||||
node_base,
|
node_base,
|
||||||
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||||
topic_name,
|
topic_name,
|
||||||
options.template to_rcl_subscription_options<rclcpp::SerializedMessage>(qos),
|
options.to_rcl_subscription_options(qos),
|
||||||
true),
|
options.event_callbacks,
|
||||||
|
options.use_default_callbacks,
|
||||||
|
SubscriptionType::SERIALIZED_MESSAGE),
|
||||||
callback_(callback),
|
callback_(callback),
|
||||||
ts_lib_(ts_lib)
|
ts_lib_(ts_lib)
|
||||||
{
|
{}
|
||||||
// This is unfortunately duplicated with the code in subscription.hpp.
|
|
||||||
// TODO(nnmm): Deduplicate by moving this into SubscriptionBase.
|
|
||||||
if (options.event_callbacks.deadline_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options.event_callbacks.deadline_callback,
|
|
||||||
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
|
|
||||||
}
|
|
||||||
if (options.event_callbacks.liveliness_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options.event_callbacks.liveliness_callback,
|
|
||||||
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
|
|
||||||
}
|
|
||||||
if (options.event_callbacks.incompatible_qos_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options.event_callbacks.incompatible_qos_callback,
|
|
||||||
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
|
|
||||||
} else if (options.use_default_callbacks) {
|
|
||||||
// Register default callback when not specified
|
|
||||||
try {
|
|
||||||
this->add_event_handler(
|
|
||||||
[this](QOSRequestedIncompatibleQoSInfo & info) {
|
|
||||||
this->default_incompatible_qos_callback(info);
|
|
||||||
},
|
|
||||||
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
|
|
||||||
} catch (UnsupportedEventTypeException & /*exc*/) {
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (options.event_callbacks.message_lost_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options.event_callbacks.message_lost_callback,
|
|
||||||
RCL_SUBSCRIPTION_MESSAGE_LOST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
virtual ~GenericSubscription() = default;
|
virtual ~GenericSubscription() = default;
|
||||||
@@ -155,6 +123,32 @@ public:
|
|||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
|
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
|
||||||
|
|
||||||
|
|
||||||
|
// DYNAMIC TYPE ==================================================================================
|
||||||
|
// TODO(methylDragon): Reorder later
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr get_shared_dynamic_message_type()
|
||||||
|
override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr get_shared_dynamic_message() override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
|
||||||
|
get_shared_dynamic_serialization_support() override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void return_dynamic_message(
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void handle_dynamic_message(
|
||||||
|
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
|
||||||
|
const rclcpp::MessageInfo & message_info) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RCLCPP_DISABLE_COPY(GenericSubscription)
|
RCLCPP_DISABLE_COPY(GenericSubscription)
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
@@ -122,6 +123,7 @@ private:
|
|||||||
: name_(new std::string(name)) {}
|
: name_(new std::string(name)) {}
|
||||||
|
|
||||||
std::shared_ptr<const std::string> name_;
|
std::shared_ptr<const std::string> name_;
|
||||||
|
std::shared_ptr<std::pair<std::string, std::string>> logger_sublogger_pairname_ = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
@@ -157,13 +159,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
Logger
|
Logger
|
||||||
get_child(const std::string & suffix)
|
get_child(const std::string & suffix);
|
||||||
{
|
|
||||||
if (!name_) {
|
|
||||||
return Logger();
|
|
||||||
}
|
|
||||||
return Logger(*name_ + "." + suffix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set level for current logger.
|
/// Set level for current logger.
|
||||||
/**
|
/**
|
||||||
@@ -174,6 +170,24 @@ public:
|
|||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
void
|
void
|
||||||
set_level(Level level);
|
set_level(Level level);
|
||||||
|
|
||||||
|
/// Get effective level for current logger.
|
||||||
|
/**
|
||||||
|
* The effective level is determined as the severity level of
|
||||||
|
* the logger if it is set, otherwise it is the first specified severity
|
||||||
|
* level of the logger's ancestors, starting with its closest ancestor.
|
||||||
|
* The ancestor hierarchy is signified by logger names being separated by dots:
|
||||||
|
* a logger named `x` is an ancestor of `x.y`, and both `x` and `x.y` are
|
||||||
|
* ancestors of `x.y.z`, etc.
|
||||||
|
* If the level has not been set for the logger nor any of its
|
||||||
|
* ancestors, the default level is used.
|
||||||
|
*
|
||||||
|
* \throws rclcpp::exceptions::RCLError if any error happens.
|
||||||
|
* \return Level for the current logger.
|
||||||
|
*/
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
Level
|
||||||
|
get_effective_level() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|||||||
@@ -740,17 +740,21 @@ public:
|
|||||||
/**
|
/**
|
||||||
* If the parameter has not been declared, then this method may throw the
|
* If the parameter has not been declared, then this method may throw the
|
||||||
* rclcpp::exceptions::ParameterNotDeclaredException exception.
|
* rclcpp::exceptions::ParameterNotDeclaredException exception.
|
||||||
|
* If the parameter has not been initialized, then this method may throw the
|
||||||
|
* rclcpp::exceptions::ParameterUninitializedException exception.
|
||||||
*
|
*
|
||||||
* If undeclared parameters are allowed, see the node option
|
* If undeclared parameters are allowed, see the node option
|
||||||
* rclcpp::NodeOptions::allow_undeclared_parameters, then this method will
|
* rclcpp::NodeOptions::allow_undeclared_parameters, then this method will
|
||||||
* not throw an exception, and instead return a default initialized
|
* not throw the rclcpp::exceptions::ParameterNotDeclaredException exception,
|
||||||
* rclcpp::Parameter, which has a type of
|
* and instead return a default initialized rclcpp::Parameter, which has a type of
|
||||||
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
||||||
*
|
*
|
||||||
* \param[in] name The name of the parameter to get.
|
* \param[in] name The name of the parameter to get.
|
||||||
* \return The requested parameter inside of a rclcpp parameter object.
|
* \return The requested parameter inside of a rclcpp parameter object.
|
||||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
|
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
|
||||||
* has not been declared and undeclared parameters are not allowed.
|
* has not been declared and undeclared parameters are not allowed.
|
||||||
|
* \throws rclcpp::exceptions::ParameterUninitializedException if the parameter
|
||||||
|
* has not been initialized.
|
||||||
*/
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
rclcpp::Parameter
|
rclcpp::Parameter
|
||||||
@@ -834,12 +838,12 @@ public:
|
|||||||
|
|
||||||
/// Return the parameters by the given parameter names.
|
/// Return the parameters by the given parameter names.
|
||||||
/**
|
/**
|
||||||
* Like get_parameters(), this method may throw the
|
* Like get_parameter(const std::string &), this method may throw the
|
||||||
* rclcpp::exceptions::ParameterNotDeclaredException exception if the
|
* rclcpp::exceptions::ParameterNotDeclaredException exception if the
|
||||||
* requested parameter has not been declared and undeclared parameters are
|
* requested parameter has not been declared and undeclared parameters are
|
||||||
* not allowed.
|
* not allowed, and may throw the rclcpp::exceptions::ParameterUninitializedException exception.
|
||||||
*
|
*
|
||||||
* Also like get_parameters(), if undeclared parameters are allowed and the
|
* Also like get_parameter(const std::string &), if undeclared parameters are allowed and the
|
||||||
* parameter has not been declared, then the corresponding rclcpp::Parameter
|
* parameter has not been declared, then the corresponding rclcpp::Parameter
|
||||||
* will be default initialized and therefore have the type
|
* will be default initialized and therefore have the type
|
||||||
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
||||||
@@ -849,6 +853,8 @@ public:
|
|||||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any of the
|
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any of the
|
||||||
* parameters have not been declared and undeclared parameters are not
|
* parameters have not been declared and undeclared parameters are not
|
||||||
* allowed.
|
* allowed.
|
||||||
|
* \throws rclcpp::exceptions::ParameterUninitializedException if any of the
|
||||||
|
* parameters have not been initialized.
|
||||||
*/
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
std::vector<rclcpp::Parameter>
|
std::vector<rclcpp::Parameter>
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
|
||||||
|
#define RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <tuple>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace node_interfaces
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
// Support and Helper template classes for the NodeInterfaces class.
|
||||||
|
|
||||||
|
template<typename NodeT, typename ... Ts>
|
||||||
|
std::tuple<std::shared_ptr<Ts>...>
|
||||||
|
init_tuple(NodeT & n);
|
||||||
|
|
||||||
|
/// Stores the interfaces in a tuple, provides constructors, and getters.
|
||||||
|
template<typename ... InterfaceTs>
|
||||||
|
struct NodeInterfacesStorage
|
||||||
|
{
|
||||||
|
template<typename NodeT>
|
||||||
|
NodeInterfacesStorage(NodeT & node) // NOLINT(runtime/explicit)
|
||||||
|
: interfaces_(init_tuple<decltype(node), InterfaceTs ...>(node))
|
||||||
|
{}
|
||||||
|
|
||||||
|
NodeInterfacesStorage()
|
||||||
|
: interfaces_()
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit NodeInterfacesStorage(std::shared_ptr<InterfaceTs>... args)
|
||||||
|
: interfaces_(args ...)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/// Individual Node Interface non-const getter.
|
||||||
|
template<typename NodeInterfaceT>
|
||||||
|
std::shared_ptr<NodeInterfaceT>
|
||||||
|
get()
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
(std::is_same_v<NodeInterfaceT, InterfaceTs>|| ...),
|
||||||
|
"NodeInterfaces class does not contain given NodeInterfaceT");
|
||||||
|
return std::get<std::shared_ptr<NodeInterfaceT>>(interfaces_);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Individual Node Interface const getter.
|
||||||
|
template<typename NodeInterfaceT>
|
||||||
|
std::shared_ptr<const NodeInterfaceT>
|
||||||
|
get() const
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
(std::is_same_v<NodeInterfaceT, InterfaceTs>|| ...),
|
||||||
|
"NodeInterfaces class does not contain given NodeInterfaceT");
|
||||||
|
return std::get<std::shared_ptr<NodeInterfaceT>>(interfaces_);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::tuple<std::shared_ptr<InterfaceTs>...> interfaces_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Prototype of NodeInterfacesSupports.
|
||||||
|
/**
|
||||||
|
* Should read NodeInterfacesSupports<..., T, ...> as "NodeInterfaces supports T", and
|
||||||
|
* if NodeInterfacesSupport is specialized for T, the is_supported should be
|
||||||
|
* set to std::true_type, but by default it is std::false_type, which will
|
||||||
|
* lead to a compiler error when trying to use T with NodeInterfaces.
|
||||||
|
*/
|
||||||
|
template<typename StorageClassT, typename ... Ts>
|
||||||
|
struct NodeInterfacesSupports;
|
||||||
|
|
||||||
|
/// Prototype of NodeInterfacesSupportCheck template meta-function.
|
||||||
|
/**
|
||||||
|
* This meta-function checks that all the types given are supported,
|
||||||
|
* throwing a more human-readable error if an unsupported type is used.
|
||||||
|
*/
|
||||||
|
template<typename StorageClassT, typename ... InterfaceTs>
|
||||||
|
struct NodeInterfacesSupportCheck;
|
||||||
|
|
||||||
|
/// Iterating specialization that ensures classes are supported and inherited.
|
||||||
|
template<typename StorageClassT, typename NextInterfaceT, typename ... RemainingInterfaceTs>
|
||||||
|
struct NodeInterfacesSupportCheck<StorageClassT, NextInterfaceT, RemainingInterfaceTs ...>
|
||||||
|
: public NodeInterfacesSupportCheck<StorageClassT, RemainingInterfaceTs ...>
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
NodeInterfacesSupports<StorageClassT, NextInterfaceT>::is_supported::value,
|
||||||
|
"given NodeInterfaceT is not supported by rclcpp::node_interfaces::NodeInterfaces");
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Terminating case when there are no more "RemainingInterfaceTs".
|
||||||
|
template<typename StorageClassT>
|
||||||
|
struct NodeInterfacesSupportCheck<StorageClassT>
|
||||||
|
{};
|
||||||
|
|
||||||
|
/// Default specialization, needs to be specialized for each supported interface.
|
||||||
|
template<typename StorageClassT, typename ... RemainingInterfaceTs>
|
||||||
|
struct NodeInterfacesSupports
|
||||||
|
{
|
||||||
|
// Specializations need to set this to std::true_type in addition to other interfaces.
|
||||||
|
using is_supported = std::false_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Terminating specialization of NodeInterfacesSupports.
|
||||||
|
template<typename StorageClassT>
|
||||||
|
struct NodeInterfacesSupports<StorageClassT>
|
||||||
|
: public StorageClassT
|
||||||
|
{
|
||||||
|
/// Perfect forwarding constructor to get arguments down to StorageClassT.
|
||||||
|
template<typename ... ArgsT>
|
||||||
|
explicit NodeInterfacesSupports(ArgsT && ... args)
|
||||||
|
: StorageClassT(std::forward<ArgsT>(args) ...)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper functions to initialize the tuple in NodeInterfaces.
|
||||||
|
|
||||||
|
template<typename StorageClassT, typename ElementT, typename TupleT, typename NodeT>
|
||||||
|
void
|
||||||
|
init_element(TupleT & t, NodeT & n)
|
||||||
|
{
|
||||||
|
std::get<std::shared_ptr<ElementT>>(t) =
|
||||||
|
NodeInterfacesSupports<StorageClassT, ElementT>::get_from_node_like(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename NodeT, typename ... Ts>
|
||||||
|
std::tuple<std::shared_ptr<Ts>...>
|
||||||
|
init_tuple(NodeT & n)
|
||||||
|
{
|
||||||
|
using StorageClassT = NodeInterfacesStorage<Ts ...>;
|
||||||
|
std::tuple<std::shared_ptr<Ts>...> t;
|
||||||
|
(init_element<StorageClassT, Ts>(t, n), ...);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Macro for creating specializations with less boilerplate.
|
||||||
|
/**
|
||||||
|
* You can use this macro to add support for your interface class if:
|
||||||
|
*
|
||||||
|
* - The standard getter is get_node_{NodeInterfaceName}_interface(), and
|
||||||
|
* - the getter returns a non-const shared_ptr<{NodeInterfaceType}>
|
||||||
|
*
|
||||||
|
* Examples of using this can be seen in the standard node interface headers
|
||||||
|
* in rclcpp, e.g. rclcpp/node_interfaces/node_base_interface.hpp has:
|
||||||
|
*
|
||||||
|
* RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)
|
||||||
|
*
|
||||||
|
* If your interface has a non-standard getter, or you want to instrument it or
|
||||||
|
* something like that, then you'll need to create your own specialization of
|
||||||
|
* the NodeInterfacesSupports struct without this macro.
|
||||||
|
*/
|
||||||
|
#define RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(NodeInterfaceType, NodeInterfaceName) \
|
||||||
|
namespace rclcpp::node_interfaces::detail { \
|
||||||
|
template<typename StorageClassT, typename ... RemainingInterfaceTs> \
|
||||||
|
struct NodeInterfacesSupports< \
|
||||||
|
StorageClassT, \
|
||||||
|
NodeInterfaceType, \
|
||||||
|
RemainingInterfaceTs ...> \
|
||||||
|
: public NodeInterfacesSupports<StorageClassT, RemainingInterfaceTs ...> \
|
||||||
|
{ \
|
||||||
|
using is_supported = std::true_type; \
|
||||||
|
\
|
||||||
|
template<typename NodeT> \
|
||||||
|
static \
|
||||||
|
std::shared_ptr<NodeInterfaceType> \
|
||||||
|
get_from_node_like(NodeT & node_like) \
|
||||||
|
{ \
|
||||||
|
return node_like.get_node_ ## NodeInterfaceName ## _interface(); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Perfect forwarding constructor to get arguments down to StorageClassT (eventually). */ \
|
||||||
|
template<typename ... ArgsT> \
|
||||||
|
explicit NodeInterfacesSupports(ArgsT && ... args) \
|
||||||
|
: NodeInterfacesSupports<StorageClassT, RemainingInterfaceTs ...>( \
|
||||||
|
std::forward<ArgsT>(args) ...) \
|
||||||
|
{} \
|
||||||
|
\
|
||||||
|
std::shared_ptr<NodeInterfaceType> \
|
||||||
|
get_node_ ## NodeInterfaceName ## _interface() \
|
||||||
|
{ \
|
||||||
|
return StorageClassT::template get<NodeInterfaceType>(); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
} // namespace rclcpp::node_interfaces::detail
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace node_interfaces
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||||
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||||
|
|
||||||
#include <functional>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|||||||
@@ -15,10 +15,10 @@
|
|||||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||||
#define RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
#define RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "rcl/node.h"
|
#include "rcl/node.h"
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "rclcpp/context.hpp"
|
#include "rclcpp/context.hpp"
|
||||||
#include "rclcpp/guard_condition.hpp"
|
#include "rclcpp/guard_condition.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
namespace rclcpp
|
namespace rclcpp
|
||||||
@@ -177,4 +178,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
|
#ifndef RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
|
||||||
#define RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
|
#define RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
|
||||||
|
|
||||||
|
#include "rcl/time.h"
|
||||||
#include "rclcpp/clock.hpp"
|
#include "rclcpp/clock.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||||
@@ -42,7 +43,8 @@ public:
|
|||||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
||||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
|
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
|
||||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging);
|
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||||
|
rcl_clock_type_t clock_type);
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
virtual
|
virtual
|
||||||
@@ -67,7 +69,7 @@ private:
|
|||||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;
|
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;
|
||||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;
|
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;
|
||||||
|
|
||||||
rclcpp::Clock::SharedPtr ros_clock_;
|
rclcpp::Clock::SharedPtr clock_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "rclcpp/clock.hpp"
|
#include "rclcpp/clock.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
namespace rclcpp
|
namespace rclcpp
|
||||||
@@ -50,4 +51,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeClockInterface, clock)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_CLOCK_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_CLOCK_INTERFACE_HPP_
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
#ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
||||||
#define RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
#define RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
#include "rclcpp/event.hpp"
|
#include "rclcpp/event.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/qos.hpp"
|
#include "rclcpp/qos.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
@@ -382,4 +383,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeGraphInterface, graph)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
|
||||||
|
|||||||
164
rclcpp/include/rclcpp/node_interfaces/node_interfaces.hpp
Normal file
164
rclcpp/include/rclcpp/node_interfaces/node_interfaces.hpp
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
|
||||||
|
#define RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "rclcpp/detail/template_unique.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
|
|
||||||
|
#define ALL_RCLCPP_NODE_INTERFACES \
|
||||||
|
rclcpp::node_interfaces::NodeBaseInterface, \
|
||||||
|
rclcpp::node_interfaces::NodeClockInterface, \
|
||||||
|
rclcpp::node_interfaces::NodeGraphInterface, \
|
||||||
|
rclcpp::node_interfaces::NodeLoggingInterface, \
|
||||||
|
rclcpp::node_interfaces::NodeParametersInterface, \
|
||||||
|
rclcpp::node_interfaces::NodeServicesInterface, \
|
||||||
|
rclcpp::node_interfaces::NodeTimeSourceInterface, \
|
||||||
|
rclcpp::node_interfaces::NodeTimersInterface, \
|
||||||
|
rclcpp::node_interfaces::NodeTopicsInterface, \
|
||||||
|
rclcpp::node_interfaces::NodeWaitablesInterface
|
||||||
|
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
namespace node_interfaces
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/// A helper class for aggregating node interfaces.
|
||||||
|
template<typename ... InterfaceTs>
|
||||||
|
class NodeInterfaces
|
||||||
|
: public detail::NodeInterfacesSupportCheck<
|
||||||
|
detail::NodeInterfacesStorage<InterfaceTs ...>,
|
||||||
|
InterfaceTs ...
|
||||||
|
>,
|
||||||
|
public detail::NodeInterfacesSupports<
|
||||||
|
detail::NodeInterfacesStorage<InterfaceTs ...>,
|
||||||
|
InterfaceTs ...
|
||||||
|
>
|
||||||
|
{
|
||||||
|
static_assert(
|
||||||
|
0 != sizeof ...(InterfaceTs),
|
||||||
|
"must provide at least one interface as a template argument");
|
||||||
|
static_assert(
|
||||||
|
rclcpp::detail::template_unique_v<InterfaceTs ...>,
|
||||||
|
"must provide unique template parameters");
|
||||||
|
|
||||||
|
using NodeInterfacesSupportsT = detail::NodeInterfacesSupports<
|
||||||
|
detail::NodeInterfacesStorage<InterfaceTs ...>,
|
||||||
|
InterfaceTs ...
|
||||||
|
>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Create a new NodeInterfaces object using the given node-like object's interfaces.
|
||||||
|
/**
|
||||||
|
* Specify which interfaces you need by passing them as template parameters.
|
||||||
|
*
|
||||||
|
* This allows you to aggregate interfaces from different sources together to pass as a single
|
||||||
|
* aggregate object to any functions that take node interfaces or node-likes, without needing to
|
||||||
|
* templatize that function.
|
||||||
|
*
|
||||||
|
* You may also use this constructor to create a NodeInterfaces that contains a subset of
|
||||||
|
* another NodeInterfaces' interfaces.
|
||||||
|
*
|
||||||
|
* Finally, this class supports implicit conversion from node-like objects, allowing you to
|
||||||
|
* directly pass a node-like to a function that takes a NodeInterfaces object.
|
||||||
|
*
|
||||||
|
* Usage examples:
|
||||||
|
* ```cpp
|
||||||
|
* // Suppose we have some function:
|
||||||
|
* void fn(NodeInterfaces<NodeBaseInterface, NodeClockInterface> interfaces);
|
||||||
|
*
|
||||||
|
* // Then we can, explicitly:
|
||||||
|
* rclcpp::Node node("some_node");
|
||||||
|
* auto ni = NodeInterfaces<NodeBaseInterface, NodeClockInterface>(node);
|
||||||
|
* fn(ni);
|
||||||
|
*
|
||||||
|
* // But also:
|
||||||
|
* fn(node);
|
||||||
|
*
|
||||||
|
* // Subsetting a NodeInterfaces object also works!
|
||||||
|
* auto ni_base = NodeInterfaces<NodeBaseInterface>(ni);
|
||||||
|
*
|
||||||
|
* // Or aggregate them (you could aggregate interfaces from disparate node-likes)
|
||||||
|
* auto ni_aggregated = NodeInterfaces<NodeBaseInterface, NodeClockInterface>(
|
||||||
|
* node->get_node_base_interface(),
|
||||||
|
* node->get_node_clock_interface()
|
||||||
|
* )
|
||||||
|
*
|
||||||
|
* // And then to access the interfaces:
|
||||||
|
* // Get with get<>
|
||||||
|
* auto base = ni.get<NodeBaseInterface>();
|
||||||
|
*
|
||||||
|
* // Or the appropriate getter
|
||||||
|
* auto clock = ni.get_clock_interface();
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* You may use any of the standard node interfaces that come with rclcpp:
|
||||||
|
* - rclcpp::node_interfaces::NodeBaseInterface
|
||||||
|
* - rclcpp::node_interfaces::NodeClockInterface
|
||||||
|
* - rclcpp::node_interfaces::NodeGraphInterface
|
||||||
|
* - rclcpp::node_interfaces::NodeLoggingInterface
|
||||||
|
* - rclcpp::node_interfaces::NodeParametersInterface
|
||||||
|
* - rclcpp::node_interfaces::NodeServicesInterface
|
||||||
|
* - rclcpp::node_interfaces::NodeTimeSourceInterface
|
||||||
|
* - rclcpp::node_interfaces::NodeTimersInterface
|
||||||
|
* - rclcpp::node_interfaces::NodeTopicsInterface
|
||||||
|
* - rclcpp::node_interfaces::NodeWaitablesInterface
|
||||||
|
*
|
||||||
|
* Or you use custom interfaces as long as you make a template specialization
|
||||||
|
* of the rclcpp::node_interfaces::detail::NodeInterfacesSupport struct using
|
||||||
|
* the RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT macro.
|
||||||
|
*
|
||||||
|
* Usage example:
|
||||||
|
* ```RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)```
|
||||||
|
*
|
||||||
|
* If you choose not to use the helper macro, then you can specialize the
|
||||||
|
* template yourself, but you must:
|
||||||
|
*
|
||||||
|
* - Provide a template specialization of the get_from_node_like method that gets the interface
|
||||||
|
* from any node-like that stores the interface, using the node-like's getter
|
||||||
|
* - Designate the is_supported type as std::true_type using a using directive
|
||||||
|
* - Provide any number of getter methods to be used to obtain the interface with the
|
||||||
|
* NodeInterface object, noting that the getters of the storage class will apply to all
|
||||||
|
* supported interfaces.
|
||||||
|
* - The getter method names should not clash in name with any other interface getter
|
||||||
|
* specializations if those other interfaces are meant to be aggregated in the same
|
||||||
|
* NodeInterfaces object.
|
||||||
|
*
|
||||||
|
* \param[in] node Node-like object from which to get the node interfaces
|
||||||
|
*/
|
||||||
|
template<typename NodeT>
|
||||||
|
NodeInterfaces(NodeT & node) // NOLINT(runtime/explicit)
|
||||||
|
: NodeInterfacesSupportsT(node)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Create a NodeInterfaces object with no bound interfaces
|
||||||
|
NodeInterfaces()
|
||||||
|
: NodeInterfacesSupportsT()
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit NodeInterfaces(std::shared_ptr<InterfaceTs>... args)
|
||||||
|
: NodeInterfacesSupportsT(args ...)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace node_interfaces
|
||||||
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
#endif // RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "rclcpp/logger.hpp"
|
#include "rclcpp/logger.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
namespace rclcpp
|
namespace rclcpp
|
||||||
@@ -58,4 +59,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeLoggingInterface, logging)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_LOGGING_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_LOGGING_INTERFACE_HPP_
|
||||||
|
|||||||
@@ -15,9 +15,10 @@
|
|||||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
||||||
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <list>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||||
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "rcl_interfaces/msg/set_parameters_result.hpp"
|
#include "rcl_interfaces/msg/set_parameters_result.hpp"
|
||||||
|
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/parameter.hpp"
|
#include "rclcpp/parameter.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
@@ -276,4 +277,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeParametersInterface, parameters)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "rclcpp/callback_group.hpp"
|
#include "rclcpp/callback_group.hpp"
|
||||||
#include "rclcpp/client.hpp"
|
#include "rclcpp/client.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/service.hpp"
|
#include "rclcpp/service.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
@@ -62,4 +63,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeServicesInterface, services)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#define RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
|
#define RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
|
||||||
|
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
namespace rclcpp
|
namespace rclcpp
|
||||||
@@ -37,4 +38,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeTimeSourceInterface, time_source)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "rclcpp/callback_group.hpp"
|
#include "rclcpp/callback_group.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/timer.hpp"
|
#include "rclcpp/timer.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
@@ -47,4 +48,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeTimersInterface, timers)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TIMERS_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_TIMERS_INTERFACE_HPP_
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
#ifndef RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||||
#define RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
#define RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "rcl/publisher.h"
|
#include "rcl/publisher.h"
|
||||||
@@ -24,6 +22,7 @@
|
|||||||
|
|
||||||
#include "rclcpp/callback_group.hpp"
|
#include "rclcpp/callback_group.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||||
#include "rclcpp/publisher.hpp"
|
#include "rclcpp/publisher.hpp"
|
||||||
@@ -97,4 +96,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeTopicsInterface, topics)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "rclcpp/callback_group.hpp"
|
#include "rclcpp/callback_group.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
#include "rclcpp/waitable.hpp"
|
#include "rclcpp/waitable.hpp"
|
||||||
|
|
||||||
@@ -54,4 +55,6 @@ public:
|
|||||||
} // namespace node_interfaces
|
} // namespace node_interfaces
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|
||||||
|
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeWaitablesInterface, waitables)
|
||||||
|
|
||||||
#endif // RCLCPP__NODE_INTERFACES__NODE_WAITABLES_INTERFACE_HPP_
|
#endif // RCLCPP__NODE_INTERFACES__NODE_WAITABLES_INTERFACE_HPP_
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "rcl/time.h"
|
||||||
#include "rcl/node_options.h"
|
#include "rcl/node_options.h"
|
||||||
#include "rclcpp/context.hpp"
|
#include "rclcpp/context.hpp"
|
||||||
#include "rclcpp/contexts/default_context.hpp"
|
#include "rclcpp/contexts/default_context.hpp"
|
||||||
@@ -46,6 +47,7 @@ public:
|
|||||||
* - enable_topic_statistics = false
|
* - enable_topic_statistics = false
|
||||||
* - start_parameter_services = true
|
* - start_parameter_services = true
|
||||||
* - start_parameter_event_publisher = true
|
* - start_parameter_event_publisher = true
|
||||||
|
* - clock_type = RCL_ROS_TIME
|
||||||
* - clock_qos = rclcpp::ClockQoS()
|
* - clock_qos = rclcpp::ClockQoS()
|
||||||
* - use_clock_thread = true
|
* - use_clock_thread = true
|
||||||
* - rosout_qos = rclcpp::RosoutQoS()
|
* - rosout_qos = rclcpp::RosoutQoS()
|
||||||
@@ -246,6 +248,19 @@ public:
|
|||||||
NodeOptions &
|
NodeOptions &
|
||||||
start_parameter_event_publisher(bool start_parameter_event_publisher);
|
start_parameter_event_publisher(bool start_parameter_event_publisher);
|
||||||
|
|
||||||
|
/// Return a reference to the clock type.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
const rcl_clock_type_t &
|
||||||
|
clock_type() const;
|
||||||
|
|
||||||
|
/// Set the clock type.
|
||||||
|
/**
|
||||||
|
* The clock type to be used by the node.
|
||||||
|
*/
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
NodeOptions &
|
||||||
|
clock_type(const rcl_clock_type_t & clock_type);
|
||||||
|
|
||||||
/// Return a reference to the clock QoS.
|
/// Return a reference to the clock QoS.
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
const rclcpp::QoS &
|
const rclcpp::QoS &
|
||||||
@@ -400,6 +415,8 @@ private:
|
|||||||
|
|
||||||
bool start_parameter_event_publisher_ {true};
|
bool start_parameter_event_publisher_ {true};
|
||||||
|
|
||||||
|
rcl_clock_type_t clock_type_ {RCL_ROS_TIME};
|
||||||
|
|
||||||
rclcpp::QoS clock_qos_ = rclcpp::ClockQoS();
|
rclcpp::QoS clock_qos_ = rclcpp::ClockQoS();
|
||||||
|
|
||||||
bool use_clock_thread_ {true};
|
bool use_clock_thread_ {true};
|
||||||
|
|||||||
@@ -131,40 +131,16 @@ public:
|
|||||||
node_base,
|
node_base,
|
||||||
topic,
|
topic,
|
||||||
rclcpp::get_message_type_support_handle<MessageT>(),
|
rclcpp::get_message_type_support_handle<MessageT>(),
|
||||||
options.template to_rcl_publisher_options<MessageT>(qos)),
|
options.template to_rcl_publisher_options<MessageT>(qos),
|
||||||
|
// NOTE(methylDragon): Passing these args separately is necessary for event binding
|
||||||
|
options.event_callbacks,
|
||||||
|
options.use_default_callbacks),
|
||||||
options_(options),
|
options_(options),
|
||||||
published_type_allocator_(*options.get_allocator()),
|
published_type_allocator_(*options.get_allocator()),
|
||||||
ros_message_type_allocator_(*options.get_allocator())
|
ros_message_type_allocator_(*options.get_allocator())
|
||||||
{
|
{
|
||||||
allocator::set_allocator_for_deleter(&published_type_deleter_, &published_type_allocator_);
|
allocator::set_allocator_for_deleter(&published_type_deleter_, &published_type_allocator_);
|
||||||
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
||||||
|
|
||||||
if (options_.event_callbacks.deadline_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options_.event_callbacks.deadline_callback,
|
|
||||||
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
|
|
||||||
}
|
|
||||||
if (options_.event_callbacks.liveliness_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options_.event_callbacks.liveliness_callback,
|
|
||||||
RCL_PUBLISHER_LIVELINESS_LOST);
|
|
||||||
}
|
|
||||||
if (options_.event_callbacks.incompatible_qos_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options_.event_callbacks.incompatible_qos_callback,
|
|
||||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
|
||||||
} else if (options_.use_default_callbacks) {
|
|
||||||
// Register default callback when not specified
|
|
||||||
try {
|
|
||||||
this->add_event_handler(
|
|
||||||
[this](QOSOfferedIncompatibleQoSInfo & info) {
|
|
||||||
this->default_incompatible_qos_callback(info);
|
|
||||||
},
|
|
||||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
|
||||||
} catch (UnsupportedEventTypeException & /*exc*/) {
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Setup continues in the post construction method, post_init_setup().
|
// Setup continues in the post construction method, post_init_setup().
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -405,10 +381,6 @@ public:
|
|||||||
if (!loaned_msg.is_valid()) {
|
if (!loaned_msg.is_valid()) {
|
||||||
throw std::runtime_error("loaned message is not valid");
|
throw std::runtime_error("loaned message is not valid");
|
||||||
}
|
}
|
||||||
if (intra_process_is_enabled_) {
|
|
||||||
// TODO(Karsten1987): support loaned message passed by intraprocess
|
|
||||||
throw std::runtime_error("storing loaned messages in intra process is not supported yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify that publisher supports loaned messages
|
// verify that publisher supports loaned messages
|
||||||
// TODO(Karsten1987): This case separation has to be done in rclcpp
|
// TODO(Karsten1987): This case separation has to be done in rclcpp
|
||||||
@@ -422,7 +394,7 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
// we don't release the ownership, let the middleware copy the ros message
|
// we don't release the ownership, let the middleware copy the ros message
|
||||||
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
|
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
|
||||||
this->do_inter_process_publish(loaned_msg.get());
|
this->publish(loaned_msg.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
#include "rclcpp/network_flow_endpoint.hpp"
|
#include "rclcpp/network_flow_endpoint.hpp"
|
||||||
#include "rclcpp/qos.hpp"
|
#include "rclcpp/qos.hpp"
|
||||||
#include "rclcpp/qos_event.hpp"
|
#include "rclcpp/event_handler.hpp"
|
||||||
#include "rclcpp/type_support_decl.hpp"
|
#include "rclcpp/type_support_decl.hpp"
|
||||||
#include "rclcpp/visibility_control.hpp"
|
#include "rclcpp/visibility_control.hpp"
|
||||||
#include "rcpputils/time.hpp"
|
#include "rcpputils/time.hpp"
|
||||||
@@ -78,11 +78,18 @@ public:
|
|||||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||||
const std::string & topic,
|
const std::string & topic,
|
||||||
const rosidl_message_type_support_t & type_support,
|
const rosidl_message_type_support_t & type_support,
|
||||||
const rcl_publisher_options_t & publisher_options);
|
const rcl_publisher_options_t & publisher_options,
|
||||||
|
const PublisherEventCallbacks & event_callbacks,
|
||||||
|
bool use_default_callbacks);
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
virtual ~PublisherBase();
|
virtual ~PublisherBase();
|
||||||
|
|
||||||
|
/// Add event handlers for passed in event_callbacks.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
bind_event_callbacks(const PublisherEventCallbacks & event_callbacks, bool use_default_callbacks);
|
||||||
|
|
||||||
/// Get the topic that this publisher publishes on.
|
/// Get the topic that this publisher publishes on.
|
||||||
/** \return The topic name. */
|
/** \return The topic name. */
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
@@ -117,7 +124,7 @@ public:
|
|||||||
/** \return The map of QoS event handlers. */
|
/** \return The map of QoS event handlers. */
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
const
|
const
|
||||||
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
|
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
|
||||||
get_event_handlers() const;
|
get_event_handlers() const;
|
||||||
|
|
||||||
/// Get subscription count
|
/// Get subscription count
|
||||||
@@ -269,7 +276,7 @@ public:
|
|||||||
* If you want more information available in the callback, like the qos event
|
* If you want more information available in the callback, like the qos event
|
||||||
* or other information, you may use a lambda with captures or std::bind.
|
* or other information, you may use a lambda with captures or std::bind.
|
||||||
*
|
*
|
||||||
* \sa rclcpp::QOSEventHandlerBase::set_on_ready_callback
|
* \sa rclcpp::EventHandlerBase::set_on_ready_callback
|
||||||
*
|
*
|
||||||
* \param[in] callback functor to be called when a new event occurs
|
* \param[in] callback functor to be called when a new event occurs
|
||||||
* \param[in] event_type identifier for the qos event we want to attach the callback to
|
* \param[in] event_type identifier for the qos event we want to attach the callback to
|
||||||
@@ -320,7 +327,7 @@ protected:
|
|||||||
const EventCallbackT & callback,
|
const EventCallbackT & callback,
|
||||||
const rcl_publisher_event_type_t event_type)
|
const rcl_publisher_event_type_t event_type)
|
||||||
{
|
{
|
||||||
auto handler = std::make_shared<QOSEventHandler<EventCallbackT,
|
auto handler = std::make_shared<EventHandler<EventCallbackT,
|
||||||
std::shared_ptr<rcl_publisher_t>>>(
|
std::shared_ptr<rcl_publisher_t>>>(
|
||||||
callback,
|
callback,
|
||||||
rcl_publisher_event_init,
|
rcl_publisher_event_init,
|
||||||
@@ -332,12 +339,15 @@ protected:
|
|||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
void default_incompatible_qos_callback(QOSOfferedIncompatibleQoSInfo & info) const;
|
void default_incompatible_qos_callback(QOSOfferedIncompatibleQoSInfo & info) const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void default_incompatible_type_callback(IncompatibleTypeInfo & info) const;
|
||||||
|
|
||||||
std::shared_ptr<rcl_node_t> rcl_node_handle_;
|
std::shared_ptr<rcl_node_t> rcl_node_handle_;
|
||||||
|
|
||||||
std::shared_ptr<rcl_publisher_t> publisher_handle_;
|
std::shared_ptr<rcl_publisher_t> publisher_handle_;
|
||||||
|
|
||||||
std::unordered_map<rcl_publisher_event_type_t,
|
std::unordered_map<rcl_publisher_event_type_t,
|
||||||
std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
|
std::shared_ptr<rclcpp::EventHandlerBase>> event_handlers_;
|
||||||
|
|
||||||
using IntraProcessManagerWeakPtr =
|
using IntraProcessManagerWeakPtr =
|
||||||
std::weak_ptr<rclcpp::experimental::IntraProcessManager>;
|
std::weak_ptr<rclcpp::experimental::IntraProcessManager>;
|
||||||
@@ -348,6 +358,8 @@ protected:
|
|||||||
rmw_gid_t rmw_gid_;
|
rmw_gid_t rmw_gid_;
|
||||||
|
|
||||||
const rosidl_message_type_support_t type_support_;
|
const rosidl_message_type_support_t type_support_;
|
||||||
|
|
||||||
|
const PublisherEventCallbacks event_callbacks_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "rclcpp/detail/rmw_implementation_specific_publisher_payload.hpp"
|
#include "rclcpp/detail/rmw_implementation_specific_publisher_payload.hpp"
|
||||||
#include "rclcpp/intra_process_setting.hpp"
|
#include "rclcpp/intra_process_setting.hpp"
|
||||||
#include "rclcpp/qos.hpp"
|
#include "rclcpp/qos.hpp"
|
||||||
#include "rclcpp/qos_event.hpp"
|
#include "rclcpp/event_handler.hpp"
|
||||||
#include "rclcpp/qos_overriding_options.hpp"
|
#include "rclcpp/qos_overriding_options.hpp"
|
||||||
|
|
||||||
namespace rclcpp
|
namespace rclcpp
|
||||||
|
|||||||
@@ -80,7 +80,9 @@ struct RCLCPP_PUBLIC QoSInitialization
|
|||||||
size_t depth;
|
size_t depth;
|
||||||
|
|
||||||
/// Constructor which takes both a history policy and a depth (even if it would be unused).
|
/// Constructor which takes both a history policy and a depth (even if it would be unused).
|
||||||
QoSInitialization(rmw_qos_history_policy_t history_policy_arg, size_t depth_arg);
|
QoSInitialization(
|
||||||
|
rmw_qos_history_policy_t history_policy_arg, size_t depth_arg,
|
||||||
|
bool print_depth_warning = true);
|
||||||
|
|
||||||
/// Create a QoSInitialization from an existing rmw_qos_profile_t, using its history and depth.
|
/// Create a QoSInitialization from an existing rmw_qos_profile_t, using its history and depth.
|
||||||
static
|
static
|
||||||
@@ -97,7 +99,7 @@ struct RCLCPP_PUBLIC KeepAll : public rclcpp::QoSInitialization
|
|||||||
/// Use to initialize the QoS with the keep_last history setting and the given depth.
|
/// Use to initialize the QoS with the keep_last history setting and the given depth.
|
||||||
struct RCLCPP_PUBLIC KeepLast : public rclcpp::QoSInitialization
|
struct RCLCPP_PUBLIC KeepLast : public rclcpp::QoSInitialization
|
||||||
{
|
{
|
||||||
explicit KeepLast(size_t depth);
|
explicit KeepLast(size_t depth, bool print_depth_warning = true);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Encapsulation of Quality of Service settings.
|
/// Encapsulation of Quality of Service settings.
|
||||||
|
|||||||
@@ -15,277 +15,8 @@
|
|||||||
#ifndef RCLCPP__QOS_EVENT_HPP_
|
#ifndef RCLCPP__QOS_EVENT_HPP_
|
||||||
#define RCLCPP__QOS_EVENT_HPP_
|
#define RCLCPP__QOS_EVENT_HPP_
|
||||||
|
|
||||||
#include <functional>
|
#warning This header is obsolete, please include rclcpp/event_handler.hpp instead
|
||||||
#include <memory>
|
|
||||||
#include <mutex>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "rcl/error_handling.h"
|
#include "rclcpp/event_handler.hpp"
|
||||||
#include "rcl/event_callback.h"
|
|
||||||
#include "rmw/impl/cpp/demangle.hpp"
|
|
||||||
#include "rmw/incompatible_qos_events_statuses.h"
|
|
||||||
|
|
||||||
#include "rcutils/logging_macros.h"
|
|
||||||
|
|
||||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
|
||||||
#include "rclcpp/exceptions.hpp"
|
|
||||||
#include "rclcpp/function_traits.hpp"
|
|
||||||
#include "rclcpp/logging.hpp"
|
|
||||||
#include "rclcpp/waitable.hpp"
|
|
||||||
|
|
||||||
namespace rclcpp
|
|
||||||
{
|
|
||||||
|
|
||||||
using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
|
|
||||||
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
|
|
||||||
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
|
|
||||||
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
|
|
||||||
using QOSMessageLostInfo = rmw_message_lost_status_t;
|
|
||||||
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
|
|
||||||
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
|
|
||||||
|
|
||||||
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
|
|
||||||
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
|
|
||||||
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
|
|
||||||
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
|
|
||||||
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
|
|
||||||
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
|
|
||||||
using QOSRequestedIncompatibleQoSCallbackType =
|
|
||||||
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
|
|
||||||
|
|
||||||
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
|
|
||||||
struct PublisherEventCallbacks
|
|
||||||
{
|
|
||||||
QOSDeadlineOfferedCallbackType deadline_callback;
|
|
||||||
QOSLivelinessLostCallbackType liveliness_callback;
|
|
||||||
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
|
|
||||||
struct SubscriptionEventCallbacks
|
|
||||||
{
|
|
||||||
QOSDeadlineRequestedCallbackType deadline_callback;
|
|
||||||
QOSLivelinessChangedCallbackType liveliness_callback;
|
|
||||||
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
|
|
||||||
QOSMessageLostCallbackType message_lost_callback;
|
|
||||||
};
|
|
||||||
|
|
||||||
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RCLCPP_PUBLIC
|
|
||||||
UnsupportedEventTypeException(
|
|
||||||
rcl_ret_t ret,
|
|
||||||
const rcl_error_state_t * error_state,
|
|
||||||
const std::string & prefix);
|
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
|
||||||
UnsupportedEventTypeException(
|
|
||||||
const exceptions::RCLErrorBase & base_exc,
|
|
||||||
const std::string & prefix);
|
|
||||||
};
|
|
||||||
|
|
||||||
class QOSEventHandlerBase : public Waitable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class EntityType : std::size_t
|
|
||||||
{
|
|
||||||
Event,
|
|
||||||
};
|
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
|
||||||
virtual ~QOSEventHandlerBase();
|
|
||||||
|
|
||||||
/// Get the number of ready events
|
|
||||||
RCLCPP_PUBLIC
|
|
||||||
size_t
|
|
||||||
get_number_of_ready_events() override;
|
|
||||||
|
|
||||||
/// Add the Waitable to a wait set.
|
|
||||||
RCLCPP_PUBLIC
|
|
||||||
void
|
|
||||||
add_to_wait_set(rcl_wait_set_t * wait_set) override;
|
|
||||||
|
|
||||||
/// Check if the Waitable is ready.
|
|
||||||
RCLCPP_PUBLIC
|
|
||||||
bool
|
|
||||||
is_ready(rcl_wait_set_t * wait_set) override;
|
|
||||||
|
|
||||||
/// Set a callback to be called when each new event instance occurs.
|
|
||||||
/**
|
|
||||||
* The callback receives a size_t which is the number of events that occurred
|
|
||||||
* since the last time this callback was called.
|
|
||||||
* Normally this is 1, but can be > 1 if events occurred before any
|
|
||||||
* callback was set.
|
|
||||||
*
|
|
||||||
* The callback also receives an int identifier argument.
|
|
||||||
* This is needed because a Waitable may be composed of several distinct entities,
|
|
||||||
* such as subscriptions, services, etc.
|
|
||||||
* The application should provide a generic callback function that will be then
|
|
||||||
* forwarded by the waitable to all of its entities.
|
|
||||||
* Before forwarding, a different value for the identifier argument will be
|
|
||||||
* bond to the function.
|
|
||||||
* This implies that the provided callback can use the identifier to behave
|
|
||||||
* differently depending on which entity triggered the waitable to become ready.
|
|
||||||
*
|
|
||||||
* Since this callback is called from the middleware, you should aim to make
|
|
||||||
* it fast and not blocking.
|
|
||||||
* If you need to do a lot of work or wait for some other event, you should
|
|
||||||
* spin it off to another thread, otherwise you risk blocking the middleware.
|
|
||||||
*
|
|
||||||
* Calling it again will clear any previously set callback.
|
|
||||||
*
|
|
||||||
* An exception will be thrown if the callback is not callable.
|
|
||||||
*
|
|
||||||
* This function is thread-safe.
|
|
||||||
*
|
|
||||||
* If you want more information available in the callback, like the qos event
|
|
||||||
* or other information, you may use a lambda with captures or std::bind.
|
|
||||||
*
|
|
||||||
* \sa rmw_event_set_callback
|
|
||||||
* \sa rcl_event_set_callback
|
|
||||||
*
|
|
||||||
* \param[in] callback functor to be called when a new event occurs
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
set_on_ready_callback(std::function<void(size_t, int)> callback) override
|
|
||||||
{
|
|
||||||
if (!callback) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"The callback passed to set_on_ready_callback "
|
|
||||||
"is not callable.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: we bind the int identifier argument to this waitable's entity types
|
|
||||||
auto new_callback =
|
|
||||||
[callback, this](size_t number_of_events) {
|
|
||||||
try {
|
|
||||||
callback(number_of_events, static_cast<int>(EntityType::Event));
|
|
||||||
} catch (const std::exception & exception) {
|
|
||||||
RCLCPP_ERROR_STREAM(
|
|
||||||
// TODO(wjwwood): get this class access to the node logger it is associated with
|
|
||||||
rclcpp::get_logger("rclcpp"),
|
|
||||||
"rclcpp::QOSEventHandlerBase@" << this <<
|
|
||||||
" caught " << rmw::impl::cpp::demangle(exception) <<
|
|
||||||
" exception in user-provided callback for the 'on ready' callback: " <<
|
|
||||||
exception.what());
|
|
||||||
} catch (...) {
|
|
||||||
RCLCPP_ERROR_STREAM(
|
|
||||||
rclcpp::get_logger("rclcpp"),
|
|
||||||
"rclcpp::QOSEventHandlerBase@" << this <<
|
|
||||||
" caught unhandled exception in user-provided callback " <<
|
|
||||||
"for the 'on ready' callback");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
|
||||||
|
|
||||||
// Set it temporarily to the new callback, while we replace the old one.
|
|
||||||
// This two-step setting, prevents a gap where the old std::function has
|
|
||||||
// been replaced but the middleware hasn't been told about the new one yet.
|
|
||||||
set_on_new_event_callback(
|
|
||||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
|
||||||
static_cast<const void *>(&new_callback));
|
|
||||||
|
|
||||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
|
||||||
on_new_event_callback_ = new_callback;
|
|
||||||
|
|
||||||
// Set it again, now using the permanent storage.
|
|
||||||
set_on_new_event_callback(
|
|
||||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
|
||||||
static_cast<const void *>(&on_new_event_callback_));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Unset the callback registered for new events, if any.
|
|
||||||
void
|
|
||||||
clear_on_ready_callback() override
|
|
||||||
{
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
|
||||||
if (on_new_event_callback_) {
|
|
||||||
set_on_new_event_callback(nullptr, nullptr);
|
|
||||||
on_new_event_callback_ = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
RCLCPP_PUBLIC
|
|
||||||
void
|
|
||||||
set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
|
|
||||||
|
|
||||||
rcl_event_t event_handle_;
|
|
||||||
size_t wait_set_event_index_;
|
|
||||||
std::recursive_mutex callback_mutex_;
|
|
||||||
std::function<void(size_t)> on_new_event_callback_{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename EventCallbackT, typename ParentHandleT>
|
|
||||||
class QOSEventHandler : public QOSEventHandlerBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template<typename InitFuncT, typename EventTypeEnum>
|
|
||||||
QOSEventHandler(
|
|
||||||
const EventCallbackT & callback,
|
|
||||||
InitFuncT init_func,
|
|
||||||
ParentHandleT parent_handle,
|
|
||||||
EventTypeEnum event_type)
|
|
||||||
: parent_handle_(parent_handle), event_callback_(callback)
|
|
||||||
{
|
|
||||||
event_handle_ = rcl_get_zero_initialized_event();
|
|
||||||
rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
|
|
||||||
if (ret != RCL_RET_OK) {
|
|
||||||
if (ret == RCL_RET_UNSUPPORTED) {
|
|
||||||
UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
|
|
||||||
rcl_reset_error();
|
|
||||||
throw exc;
|
|
||||||
} else {
|
|
||||||
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Take data so that the callback cannot be scheduled again
|
|
||||||
std::shared_ptr<void>
|
|
||||||
take_data() override
|
|
||||||
{
|
|
||||||
EventCallbackInfoT callback_info;
|
|
||||||
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
|
|
||||||
if (ret != RCL_RET_OK) {
|
|
||||||
RCUTILS_LOG_ERROR_NAMED(
|
|
||||||
"rclcpp",
|
|
||||||
"Couldn't take event info: %s", rcl_get_error_string().str);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<void>
|
|
||||||
take_data_by_entity_id(size_t id) override
|
|
||||||
{
|
|
||||||
(void)id;
|
|
||||||
return take_data();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Execute any entities of the Waitable that are ready.
|
|
||||||
void
|
|
||||||
execute(std::shared_ptr<void> & data) override
|
|
||||||
{
|
|
||||||
if (!data) {
|
|
||||||
throw std::runtime_error("'data' is empty");
|
|
||||||
}
|
|
||||||
auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
|
|
||||||
event_callback_(*callback_ptr);
|
|
||||||
callback_ptr.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
using EventCallbackInfoT = typename std::remove_reference<typename
|
|
||||||
rclcpp::function_traits::function_traits<EventCallbackT>::template argument_type<0>>::type;
|
|
||||||
|
|
||||||
ParentHandleT parent_handle_;
|
|
||||||
EventCallbackT event_callback_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rclcpp
|
|
||||||
|
|
||||||
#endif // RCLCPP__QOS_EVENT_HPP_
|
#endif // RCLCPP__QOS_EVENT_HPP_
|
||||||
|
|||||||
@@ -117,6 +117,21 @@
|
|||||||
* - Allocator related items:
|
* - Allocator related items:
|
||||||
* - rclcpp/allocator/allocator_common.hpp
|
* - rclcpp/allocator/allocator_common.hpp
|
||||||
* - rclcpp/allocator/allocator_deleter.hpp
|
* - rclcpp/allocator/allocator_deleter.hpp
|
||||||
|
* - Dynamic typesupport wrappers
|
||||||
|
* - rclcpp::dynamic_typesupport::DynamicMessage
|
||||||
|
* - rclcpp::dynamic_typesupport::DynamicMessageType
|
||||||
|
* - rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder
|
||||||
|
* - rclcpp::dynamic_typesupport::DynamicSerializationSupport
|
||||||
|
* - rclcpp/dynamic_typesupport/dynamic_message.hpp
|
||||||
|
* - rclcpp/dynamic_typesupport/dynamic_message_type.hpp
|
||||||
|
* - rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp
|
||||||
|
* - rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp
|
||||||
|
* - Dynamic typesupport
|
||||||
|
* - rclcpp::dynamic_typesupport::DynamicMessageTypeSupport
|
||||||
|
* - rclcpp/dynamic_typesupport/dynamic_message_type_support.hpp
|
||||||
|
* - Dynamic subscription
|
||||||
|
* - rclcpp::DynamicSubscription
|
||||||
|
* - rclcpp/dynamic_subscription.hpp
|
||||||
* - Generic publisher
|
* - Generic publisher
|
||||||
* - rclcpp::Node::create_generic_publisher()
|
* - rclcpp::Node::create_generic_publisher()
|
||||||
* - rclcpp::GenericPublisher
|
* - rclcpp::GenericPublisher
|
||||||
@@ -167,4 +182,6 @@
|
|||||||
#include "rclcpp/waitable.hpp"
|
#include "rclcpp/waitable.hpp"
|
||||||
#include "rclcpp/wait_set.hpp"
|
#include "rclcpp/wait_set.hpp"
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_subscription.hpp"
|
||||||
|
|
||||||
#endif // RCLCPP__RCLCPP_HPP_
|
#endif // RCLCPP__RCLCPP_HPP_
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
// Copyright 2015 Open Source Robotics Foundation, Inc.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
// Based on: http://the-witness.net/news/2012/11/scopeexit-in-c11/
|
|
||||||
// But I changed the lambda to include by reference rather than value, see:
|
|
||||||
// http://the-witness.net/news/2012/11/scopeexit-in-c11/comment-page-1/#comment-86873
|
|
||||||
|
|
||||||
#ifndef RCLCPP__SCOPE_EXIT_HPP_
|
|
||||||
#define RCLCPP__SCOPE_EXIT_HPP_
|
|
||||||
|
|
||||||
// TODO(christophebedard) remove this header completely in I-turtle
|
|
||||||
|
|
||||||
#warning rclcpp/scope_exit.hpp has been deprecated, please use rcpputils/scope_exit.hpp instead
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
#include "rclcpp/macros.hpp"
|
|
||||||
|
|
||||||
namespace rclcpp
|
|
||||||
{
|
|
||||||
|
|
||||||
template<typename Callable>
|
|
||||||
struct ScopeExit
|
|
||||||
{
|
|
||||||
explicit ScopeExit(Callable callable)
|
|
||||||
: callable_(callable) {}
|
|
||||||
~ScopeExit() {callable_();}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Callable callable_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Callable>
|
|
||||||
ScopeExit<Callable>
|
|
||||||
make_scope_exit(Callable callable)
|
|
||||||
{
|
|
||||||
return ScopeExit<Callable>(callable);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace rclcpp
|
|
||||||
|
|
||||||
#define RCLCPP_SCOPE_EXIT(code) \
|
|
||||||
auto RCLCPP_STRING_JOIN(scope_exit_, __LINE__) = rclcpp::make_scope_exit([&]() {code;})
|
|
||||||
|
|
||||||
#endif // RCLCPP__SCOPE_EXIT_HPP_
|
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "rcl/error_handling.h"
|
#include "rcl/error_handling.h"
|
||||||
#include "rcl/event_callback.h"
|
#include "rcl/event_callback.h"
|
||||||
#include "rcl/service.h"
|
#include "rcl/service.h"
|
||||||
|
#include "rcl/service_introspection.h"
|
||||||
|
|
||||||
#include "rmw/error_handling.h"
|
#include "rmw/error_handling.h"
|
||||||
#include "rmw/impl/cpp/demangle.hpp"
|
#include "rmw/impl/cpp/demangle.hpp"
|
||||||
@@ -34,6 +35,7 @@
|
|||||||
#include "tracetools/tracetools.h"
|
#include "tracetools/tracetools.h"
|
||||||
|
|
||||||
#include "rclcpp/any_service_callback.hpp"
|
#include "rclcpp/any_service_callback.hpp"
|
||||||
|
#include "rclcpp/clock.hpp"
|
||||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||||
#include "rclcpp/exceptions.hpp"
|
#include "rclcpp/exceptions.hpp"
|
||||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||||
@@ -55,7 +57,7 @@ public:
|
|||||||
explicit ServiceBase(std::shared_ptr<rcl_node_t> node_handle);
|
explicit ServiceBase(std::shared_ptr<rcl_node_t> node_handle);
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
virtual ~ServiceBase();
|
virtual ~ServiceBase() = default;
|
||||||
|
|
||||||
/// Return the name of the service.
|
/// Return the name of the service.
|
||||||
/** \return The name of the service. */
|
/** \return The name of the service. */
|
||||||
@@ -222,7 +224,7 @@ public:
|
|||||||
// This two-step setting, prevents a gap where the old std::function has
|
// This two-step setting, prevents a gap where the old std::function has
|
||||||
// been replaced but the middleware hasn't been told about the new one yet.
|
// been replaced but the middleware hasn't been told about the new one yet.
|
||||||
set_on_new_request_callback(
|
set_on_new_request_callback(
|
||||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||||
static_cast<const void *>(&new_callback));
|
static_cast<const void *>(&new_callback));
|
||||||
|
|
||||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||||
@@ -230,7 +232,8 @@ public:
|
|||||||
|
|
||||||
// Set it again, now using the permanent storage.
|
// Set it again, now using the permanent storage.
|
||||||
set_on_new_request_callback(
|
set_on_new_request_callback(
|
||||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
rclcpp::detail::cpp_callback_trampoline<
|
||||||
|
decltype(on_new_request_callback_), const void *, size_t>,
|
||||||
static_cast<const void *>(&on_new_request_callback_));
|
static_cast<const void *>(&on_new_request_callback_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,11 +310,9 @@ public:
|
|||||||
const std::string & service_name,
|
const std::string & service_name,
|
||||||
AnyServiceCallback<ServiceT> any_callback,
|
AnyServiceCallback<ServiceT> any_callback,
|
||||||
rcl_service_options_t & service_options)
|
rcl_service_options_t & service_options)
|
||||||
: ServiceBase(node_handle), any_callback_(any_callback)
|
: ServiceBase(node_handle), any_callback_(any_callback),
|
||||||
|
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
|
||||||
{
|
{
|
||||||
using rosidl_typesupport_cpp::get_service_type_support_handle;
|
|
||||||
auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
|
|
||||||
|
|
||||||
// rcl does the static memory allocation here
|
// rcl does the static memory allocation here
|
||||||
service_handle_ = std::shared_ptr<rcl_service_t>(
|
service_handle_ = std::shared_ptr<rcl_service_t>(
|
||||||
new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
|
new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
|
||||||
@@ -330,7 +331,7 @@ public:
|
|||||||
rcl_ret_t ret = rcl_service_init(
|
rcl_ret_t ret = rcl_service_init(
|
||||||
service_handle_.get(),
|
service_handle_.get(),
|
||||||
node_handle.get(),
|
node_handle.get(),
|
||||||
service_type_support_handle,
|
srv_type_support_handle_,
|
||||||
service_name.c_str(),
|
service_name.c_str(),
|
||||||
&service_options);
|
&service_options);
|
||||||
if (ret != RCL_RET_OK) {
|
if (ret != RCL_RET_OK) {
|
||||||
@@ -370,8 +371,8 @@ public:
|
|||||||
std::shared_ptr<rcl_node_t> node_handle,
|
std::shared_ptr<rcl_node_t> node_handle,
|
||||||
std::shared_ptr<rcl_service_t> service_handle,
|
std::shared_ptr<rcl_service_t> service_handle,
|
||||||
AnyServiceCallback<ServiceT> any_callback)
|
AnyServiceCallback<ServiceT> any_callback)
|
||||||
: ServiceBase(node_handle),
|
: ServiceBase(node_handle), any_callback_(any_callback),
|
||||||
any_callback_(any_callback)
|
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
|
||||||
{
|
{
|
||||||
// check if service handle was initialized
|
// check if service handle was initialized
|
||||||
if (!rcl_service_is_valid(service_handle.get())) {
|
if (!rcl_service_is_valid(service_handle.get())) {
|
||||||
@@ -405,8 +406,8 @@ public:
|
|||||||
std::shared_ptr<rcl_node_t> node_handle,
|
std::shared_ptr<rcl_node_t> node_handle,
|
||||||
rcl_service_t * service_handle,
|
rcl_service_t * service_handle,
|
||||||
AnyServiceCallback<ServiceT> any_callback)
|
AnyServiceCallback<ServiceT> any_callback)
|
||||||
: ServiceBase(node_handle),
|
: ServiceBase(node_handle), any_callback_(any_callback),
|
||||||
any_callback_(any_callback)
|
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
|
||||||
{
|
{
|
||||||
// check if service handle was initialized
|
// check if service handle was initialized
|
||||||
if (!rcl_service_is_valid(service_handle)) {
|
if (!rcl_service_is_valid(service_handle)) {
|
||||||
@@ -486,10 +487,39 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configure client introspection.
|
||||||
|
/**
|
||||||
|
* \param[in] clock clock to use to generate introspection timestamps
|
||||||
|
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
|
||||||
|
* \param[in] introspection_state the state to set introspection to
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
configure_introspection(
|
||||||
|
Clock::SharedPtr clock, const QoS & qos_service_event_pub,
|
||||||
|
rcl_service_introspection_state_t introspection_state)
|
||||||
|
{
|
||||||
|
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
|
||||||
|
pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
|
||||||
|
|
||||||
|
rcl_ret_t ret = rcl_service_configure_service_introspection(
|
||||||
|
service_handle_.get(),
|
||||||
|
node_handle_.get(),
|
||||||
|
clock->get_clock_handle(),
|
||||||
|
srv_type_support_handle_,
|
||||||
|
pub_opts,
|
||||||
|
introspection_state);
|
||||||
|
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure service introspection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RCLCPP_DISABLE_COPY(Service)
|
RCLCPP_DISABLE_COPY(Service)
|
||||||
|
|
||||||
AnyServiceCallback<ServiceT> any_callback_;
|
AnyServiceCallback<ServiceT> any_callback_;
|
||||||
|
|
||||||
|
const rosidl_service_type_support_t * srv_type_support_handle_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "rcl/allocator.h"
|
#include "rcl/allocator.h"
|
||||||
|
|
||||||
@@ -120,8 +121,8 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < waitable_handles_.size(); ++i) {
|
for (size_t i = 0; i < waitable_handles_.size(); ++i) {
|
||||||
if (!waitable_handles_[i]->is_ready(wait_set)) {
|
if (waitable_handles_[i]->is_ready(wait_set)) {
|
||||||
waitable_handles_[i].reset();
|
waitable_triggered_handles_.emplace_back(std::move(waitable_handles_[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,10 +146,7 @@ public:
|
|||||||
timer_handles_.end()
|
timer_handles_.end()
|
||||||
);
|
);
|
||||||
|
|
||||||
waitable_handles_.erase(
|
waitable_handles_.clear();
|
||||||
std::remove(waitable_handles_.begin(), waitable_handles_.end(), nullptr),
|
|
||||||
waitable_handles_.end()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool collect_entities(const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
|
bool collect_entities(const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
|
||||||
@@ -392,8 +390,9 @@ public:
|
|||||||
rclcpp::AnyExecutable & any_exec,
|
rclcpp::AnyExecutable & any_exec,
|
||||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
|
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
|
||||||
{
|
{
|
||||||
auto it = waitable_handles_.begin();
|
auto & waitable_handles = waitable_triggered_handles_;
|
||||||
while (it != waitable_handles_.end()) {
|
auto it = waitable_handles.begin();
|
||||||
|
while (it != waitable_handles.end()) {
|
||||||
std::shared_ptr<Waitable> & waitable = *it;
|
std::shared_ptr<Waitable> & waitable = *it;
|
||||||
if (waitable) {
|
if (waitable) {
|
||||||
// Find the group for this handle and see if it can be serviced
|
// Find the group for this handle and see if it can be serviced
|
||||||
@@ -401,7 +400,7 @@ public:
|
|||||||
if (!group) {
|
if (!group) {
|
||||||
// Group was not found, meaning the waitable is not valid...
|
// Group was not found, meaning the waitable is not valid...
|
||||||
// Remove it from the ready list and continue looking
|
// Remove it from the ready list and continue looking
|
||||||
it = waitable_handles_.erase(it);
|
it = waitable_handles.erase(it);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!group->can_be_taken_from().load()) {
|
if (!group->can_be_taken_from().load()) {
|
||||||
@@ -414,11 +413,11 @@ public:
|
|||||||
any_exec.waitable = waitable;
|
any_exec.waitable = waitable;
|
||||||
any_exec.callback_group = group;
|
any_exec.callback_group = group;
|
||||||
any_exec.node_base = get_node_by_group(group, weak_groups_to_nodes);
|
any_exec.node_base = get_node_by_group(group, weak_groups_to_nodes);
|
||||||
waitable_handles_.erase(it);
|
waitable_handles.erase(it);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Else, the waitable is no longer valid, remove it and continue
|
// Else, the waitable is no longer valid, remove it and continue
|
||||||
it = waitable_handles_.erase(it);
|
it = waitable_handles.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -499,6 +498,8 @@ private:
|
|||||||
VectorRebind<std::shared_ptr<const rcl_timer_t>> timer_handles_;
|
VectorRebind<std::shared_ptr<const rcl_timer_t>> timer_handles_;
|
||||||
VectorRebind<std::shared_ptr<Waitable>> waitable_handles_;
|
VectorRebind<std::shared_ptr<Waitable>> waitable_handles_;
|
||||||
|
|
||||||
|
VectorRebind<std::shared_ptr<Waitable>> waitable_triggered_handles_;
|
||||||
|
|
||||||
std::shared_ptr<VoidAlloc> allocator_;
|
std::shared_ptr<VoidAlloc> allocator_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -140,44 +140,15 @@ public:
|
|||||||
node_base,
|
node_base,
|
||||||
type_support_handle,
|
type_support_handle,
|
||||||
topic_name,
|
topic_name,
|
||||||
options.template to_rcl_subscription_options<ROSMessageType>(qos),
|
options.to_rcl_subscription_options(qos),
|
||||||
callback.is_serialized_message_callback()),
|
// NOTE(methylDragon): Passing these args separately is necessary for event binding
|
||||||
|
options.event_callbacks,
|
||||||
|
options.use_default_callbacks,
|
||||||
|
callback.is_serialized_message_callback() ? SubscriptionType::SERIALIZED_MESSAGE : SubscriptionType::ROS_MESSAGE), // NOLINT
|
||||||
any_callback_(callback),
|
any_callback_(callback),
|
||||||
options_(options),
|
options_(options),
|
||||||
message_memory_strategy_(message_memory_strategy)
|
message_memory_strategy_(message_memory_strategy)
|
||||||
{
|
{
|
||||||
if (options_.event_callbacks.deadline_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options_.event_callbacks.deadline_callback,
|
|
||||||
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
|
|
||||||
}
|
|
||||||
if (options_.event_callbacks.liveliness_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options_.event_callbacks.liveliness_callback,
|
|
||||||
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
|
|
||||||
}
|
|
||||||
if (options_.event_callbacks.incompatible_qos_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options_.event_callbacks.incompatible_qos_callback,
|
|
||||||
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
|
|
||||||
} else if (options_.use_default_callbacks) {
|
|
||||||
// Register default callback when not specified
|
|
||||||
try {
|
|
||||||
this->add_event_handler(
|
|
||||||
[this](QOSRequestedIncompatibleQoSInfo & info) {
|
|
||||||
this->default_incompatible_qos_callback(info);
|
|
||||||
},
|
|
||||||
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
|
|
||||||
} catch (UnsupportedEventTypeException & /*exc*/) {
|
|
||||||
// pass
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (options_.event_callbacks.message_lost_callback) {
|
|
||||||
this->add_event_handler(
|
|
||||||
options_.event_callbacks.message_lost_callback,
|
|
||||||
RCL_SUBSCRIPTION_MESSAGE_LOST);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup intra process publishing if requested.
|
// Setup intra process publishing if requested.
|
||||||
if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
|
if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
|
||||||
using rclcpp::detail::resolve_intra_process_buffer_type;
|
using rclcpp::detail::resolve_intra_process_buffer_type;
|
||||||
@@ -417,6 +388,57 @@ public:
|
|||||||
return any_callback_.use_take_shared_method();
|
return any_callback_.use_take_shared_method();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DYNAMIC TYPE ==================================================================================
|
||||||
|
// TODO(methylDragon): Reorder later
|
||||||
|
// TODO(methylDragon): Implement later...
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
|
||||||
|
get_shared_dynamic_message_type() override
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"get_shared_dynamic_message_type is not implemented for Subscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
|
||||||
|
get_shared_dynamic_message() override
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"get_shared_dynamic_message is not implemented for Subscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
|
||||||
|
get_shared_dynamic_serialization_support() override
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"get_shared_dynamic_serialization_support is not implemented for Subscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
|
||||||
|
create_dynamic_message() override
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"create_dynamic_message is not implemented for Subscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
return_dynamic_message(
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override
|
||||||
|
{
|
||||||
|
(void) message;
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"return_dynamic_message is not implemented for Subscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_dynamic_message(
|
||||||
|
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
|
||||||
|
const rclcpp::MessageInfo & message_info) override
|
||||||
|
{
|
||||||
|
(void) message;
|
||||||
|
(void) message_info;
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"handle_dynamic_message is not implemented for Subscription");
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RCLCPP_DISABLE_COPY(Subscription)
|
RCLCPP_DISABLE_COPY(Subscription)
|
||||||
|
|
||||||
|
|||||||
@@ -31,13 +31,16 @@
|
|||||||
|
|
||||||
#include "rclcpp/any_subscription_callback.hpp"
|
#include "rclcpp/any_subscription_callback.hpp"
|
||||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
#include "rclcpp/experimental/intra_process_manager.hpp"
|
#include "rclcpp/experimental/intra_process_manager.hpp"
|
||||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
#include "rclcpp/message_info.hpp"
|
#include "rclcpp/message_info.hpp"
|
||||||
#include "rclcpp/network_flow_endpoint.hpp"
|
#include "rclcpp/network_flow_endpoint.hpp"
|
||||||
#include "rclcpp/qos.hpp"
|
#include "rclcpp/qos.hpp"
|
||||||
#include "rclcpp/qos_event.hpp"
|
#include "rclcpp/event_handler.hpp"
|
||||||
#include "rclcpp/serialized_message.hpp"
|
#include "rclcpp/serialized_message.hpp"
|
||||||
#include "rclcpp/subscription_content_filter_options.hpp"
|
#include "rclcpp/subscription_content_filter_options.hpp"
|
||||||
#include "rclcpp/type_support_decl.hpp"
|
#include "rclcpp/type_support_decl.hpp"
|
||||||
@@ -60,6 +63,14 @@ namespace experimental
|
|||||||
class IntraProcessManager;
|
class IntraProcessManager;
|
||||||
} // namespace experimental
|
} // namespace experimental
|
||||||
|
|
||||||
|
enum class SubscriptionType : uint8_t
|
||||||
|
{
|
||||||
|
ROS_MESSAGE = 1, // take message as ROS message and handle as ROS message
|
||||||
|
SERIALIZED_MESSAGE = 2, // take message as serialized and handle as serialized
|
||||||
|
DYNAMIC_MESSAGE_DIRECT = 3, // take message as DynamicMessage and handle as DynamicMessage
|
||||||
|
DYNAMIC_MESSAGE_FROM_SERIALIZED = 4 // take message as serialized and handle as DynamicMessage
|
||||||
|
};
|
||||||
|
|
||||||
/// Virtual base class for subscriptions. This pattern allows us to iterate over different template
|
/// Virtual base class for subscriptions. This pattern allows us to iterate over different template
|
||||||
/// specializations of Subscription, among other things.
|
/// specializations of Subscription, among other things.
|
||||||
class SubscriptionBase : public std::enable_shared_from_this<SubscriptionBase>
|
class SubscriptionBase : public std::enable_shared_from_this<SubscriptionBase>
|
||||||
@@ -76,7 +87,7 @@ public:
|
|||||||
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
|
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
|
||||||
* \param[in] topic_name Name of the topic to subscribe to.
|
* \param[in] topic_name Name of the topic to subscribe to.
|
||||||
* \param[in] subscription_options Options for the subscription.
|
* \param[in] subscription_options Options for the subscription.
|
||||||
* \param[in] is_serialized is true if the message will be delivered still serialized
|
* \param[in] subscription_type Enum flag to change how the message will be received and delivered
|
||||||
*/
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
SubscriptionBase(
|
SubscriptionBase(
|
||||||
@@ -84,12 +95,20 @@ public:
|
|||||||
const rosidl_message_type_support_t & type_support_handle,
|
const rosidl_message_type_support_t & type_support_handle,
|
||||||
const std::string & topic_name,
|
const std::string & topic_name,
|
||||||
const rcl_subscription_options_t & subscription_options,
|
const rcl_subscription_options_t & subscription_options,
|
||||||
bool is_serialized = false);
|
const SubscriptionEventCallbacks & event_callbacks,
|
||||||
|
bool use_default_callbacks,
|
||||||
|
SubscriptionType subscription_type = SubscriptionType::ROS_MESSAGE);
|
||||||
|
|
||||||
/// Destructor.
|
/// Destructor.
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
virtual ~SubscriptionBase();
|
virtual ~SubscriptionBase();
|
||||||
|
|
||||||
|
/// Add event handlers for passed in event_callbacks.
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
bind_event_callbacks(
|
||||||
|
const SubscriptionEventCallbacks & event_callbacks, bool use_default_callbacks);
|
||||||
|
|
||||||
/// Get the topic that this subscription is subscribed on.
|
/// Get the topic that this subscription is subscribed on.
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
const char *
|
const char *
|
||||||
@@ -107,7 +126,7 @@ public:
|
|||||||
/** \return The map of QoS event handlers. */
|
/** \return The map of QoS event handlers. */
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
const
|
const
|
||||||
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
|
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
|
||||||
get_event_handlers() const;
|
get_event_handlers() const;
|
||||||
|
|
||||||
/// Get the actual QoS settings, after the defaults have been determined.
|
/// Get the actual QoS settings, after the defaults have been determined.
|
||||||
@@ -219,13 +238,13 @@ public:
|
|||||||
const rosidl_message_type_support_t &
|
const rosidl_message_type_support_t &
|
||||||
get_message_type_support_handle() const;
|
get_message_type_support_handle() const;
|
||||||
|
|
||||||
/// Return if the subscription is serialized
|
/// Return the type of the subscription.
|
||||||
/**
|
/**
|
||||||
* \return `true` if the subscription is serialized, `false` otherwise
|
* \return `SubscriptionType`, which adjusts how messages are received and delivered.
|
||||||
*/
|
*/
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
bool
|
SubscriptionType
|
||||||
is_serialized() const;
|
get_subscription_type() const;
|
||||||
|
|
||||||
/// Get matching publisher count.
|
/// Get matching publisher count.
|
||||||
/** \return The number of publishers on this topic. */
|
/** \return The number of publishers on this topic. */
|
||||||
@@ -348,7 +367,7 @@ public:
|
|||||||
// This two-step setting, prevents a gap where the old std::function has
|
// This two-step setting, prevents a gap where the old std::function has
|
||||||
// been replaced but the middleware hasn't been told about the new one yet.
|
// been replaced but the middleware hasn't been told about the new one yet.
|
||||||
set_on_new_message_callback(
|
set_on_new_message_callback(
|
||||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||||
static_cast<const void *>(&new_callback));
|
static_cast<const void *>(&new_callback));
|
||||||
|
|
||||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||||
@@ -356,7 +375,8 @@ public:
|
|||||||
|
|
||||||
// Set it again, now using the permanent storage.
|
// Set it again, now using the permanent storage.
|
||||||
set_on_new_message_callback(
|
set_on_new_message_callback(
|
||||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
rclcpp::detail::cpp_callback_trampoline<
|
||||||
|
decltype(on_new_message_callback_), const void *, size_t>,
|
||||||
static_cast<const void *>(&on_new_message_callback_));
|
static_cast<const void *>(&on_new_message_callback_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +468,7 @@ public:
|
|||||||
* If you want more information available in the callback, like the qos event
|
* If you want more information available in the callback, like the qos event
|
||||||
* or other information, you may use a lambda with captures or std::bind.
|
* or other information, you may use a lambda with captures or std::bind.
|
||||||
*
|
*
|
||||||
* \sa rclcpp::QOSEventHandlerBase::set_on_ready_callback
|
* \sa rclcpp::EventHandlerBase::set_on_ready_callback
|
||||||
*
|
*
|
||||||
* \param[in] callback functor to be called when a new event occurs
|
* \param[in] callback functor to be called when a new event occurs
|
||||||
* \param[in] event_type identifier for the qos event we want to attach the callback to
|
* \param[in] event_type identifier for the qos event we want to attach the callback to
|
||||||
@@ -526,6 +546,49 @@ public:
|
|||||||
rclcpp::ContentFilterOptions
|
rclcpp::ContentFilterOptions
|
||||||
get_content_filter() const;
|
get_content_filter() const;
|
||||||
|
|
||||||
|
// DYNAMIC TYPE ==================================================================================
|
||||||
|
// TODO(methylDragon): Reorder later
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
|
||||||
|
get_shared_dynamic_message_type() = 0;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
|
||||||
|
get_shared_dynamic_message() = 0;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual
|
||||||
|
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
|
||||||
|
get_shared_dynamic_serialization_support() = 0;
|
||||||
|
|
||||||
|
/// Borrow a new serialized message (this clones!)
|
||||||
|
/** \return Shared pointer to a rclcpp::dynamic_typesupport::DynamicMessage. */
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
|
||||||
|
create_dynamic_message() = 0;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
return_dynamic_message(rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) = 0;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
handle_dynamic_message(
|
||||||
|
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
|
||||||
|
const rclcpp::MessageInfo & message_info) = 0;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
bool
|
||||||
|
take_dynamic_message(
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage & message_out,
|
||||||
|
rclcpp::MessageInfo & message_info_out);
|
||||||
|
// ===============================================================================================
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
template<typename EventCallbackT>
|
template<typename EventCallbackT>
|
||||||
void
|
void
|
||||||
@@ -533,7 +596,7 @@ protected:
|
|||||||
const EventCallbackT & callback,
|
const EventCallbackT & callback,
|
||||||
const rcl_subscription_event_type_t event_type)
|
const rcl_subscription_event_type_t event_type)
|
||||||
{
|
{
|
||||||
auto handler = std::make_shared<QOSEventHandler<EventCallbackT,
|
auto handler = std::make_shared<EventHandler<EventCallbackT,
|
||||||
std::shared_ptr<rcl_subscription_t>>>(
|
std::shared_ptr<rcl_subscription_t>>>(
|
||||||
callback,
|
callback,
|
||||||
rcl_subscription_event_init,
|
rcl_subscription_event_init,
|
||||||
@@ -546,6 +609,9 @@ protected:
|
|||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
void default_incompatible_qos_callback(QOSRequestedIncompatibleQoSInfo & info) const;
|
void default_incompatible_qos_callback(QOSRequestedIncompatibleQoSInfo & info) const;
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void default_incompatible_type_callback(IncompatibleTypeInfo & info) const;
|
||||||
|
|
||||||
RCLCPP_PUBLIC
|
RCLCPP_PUBLIC
|
||||||
bool
|
bool
|
||||||
matches_any_intra_process_publishers(const rmw_gid_t * sender_gid) const;
|
matches_any_intra_process_publishers(const rmw_gid_t * sender_gid) const;
|
||||||
@@ -556,28 +622,34 @@ protected:
|
|||||||
|
|
||||||
rclcpp::node_interfaces::NodeBaseInterface * const node_base_;
|
rclcpp::node_interfaces::NodeBaseInterface * const node_base_;
|
||||||
|
|
||||||
|
// TODO(methylDragon): Remove if we don't need this
|
||||||
|
// rclcpp::node_interfaces::NodeGraphInterface * const node_graph_;
|
||||||
|
// rclcpp::node_interfaces::NodeServicesInterface * const node_services_;
|
||||||
|
|
||||||
std::shared_ptr<rcl_node_t> node_handle_;
|
std::shared_ptr<rcl_node_t> node_handle_;
|
||||||
std::shared_ptr<rcl_subscription_t> subscription_handle_;
|
std::shared_ptr<rcl_subscription_t> subscription_handle_;
|
||||||
std::shared_ptr<rcl_subscription_t> intra_process_subscription_handle_;
|
std::shared_ptr<rcl_subscription_t> intra_process_subscription_handle_;
|
||||||
rclcpp::Logger node_logger_;
|
rclcpp::Logger node_logger_;
|
||||||
|
|
||||||
std::unordered_map<rcl_subscription_event_type_t,
|
std::unordered_map<rcl_subscription_event_type_t,
|
||||||
std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
|
std::shared_ptr<rclcpp::EventHandlerBase>> event_handlers_;
|
||||||
|
|
||||||
bool use_intra_process_;
|
bool use_intra_process_;
|
||||||
IntraProcessManagerWeakPtr weak_ipm_;
|
IntraProcessManagerWeakPtr weak_ipm_;
|
||||||
uint64_t intra_process_subscription_id_;
|
uint64_t intra_process_subscription_id_;
|
||||||
std::shared_ptr<rclcpp::experimental::SubscriptionIntraProcessBase> subscription_intra_process_;
|
std::shared_ptr<rclcpp::experimental::SubscriptionIntraProcessBase> subscription_intra_process_;
|
||||||
|
|
||||||
|
const SubscriptionEventCallbacks event_callbacks_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RCLCPP_DISABLE_COPY(SubscriptionBase)
|
RCLCPP_DISABLE_COPY(SubscriptionBase)
|
||||||
|
|
||||||
rosidl_message_type_support_t type_support_;
|
rosidl_message_type_support_t type_support_;
|
||||||
bool is_serialized_;
|
SubscriptionType subscription_type_;
|
||||||
|
|
||||||
std::atomic<bool> subscription_in_use_by_wait_set_{false};
|
std::atomic<bool> subscription_in_use_by_wait_set_{false};
|
||||||
std::atomic<bool> intra_process_subscription_waitable_in_use_by_wait_set_{false};
|
std::atomic<bool> intra_process_subscription_waitable_in_use_by_wait_set_{false};
|
||||||
std::unordered_map<rclcpp::QOSEventHandlerBase *,
|
std::unordered_map<rclcpp::EventHandlerBase *,
|
||||||
std::atomic<bool>> qos_events_in_use_by_wait_set_;
|
std::atomic<bool>> qos_events_in_use_by_wait_set_;
|
||||||
|
|
||||||
std::recursive_mutex callback_mutex_;
|
std::recursive_mutex callback_mutex_;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "rclcpp/intra_process_buffer_type.hpp"
|
#include "rclcpp/intra_process_buffer_type.hpp"
|
||||||
#include "rclcpp/intra_process_setting.hpp"
|
#include "rclcpp/intra_process_setting.hpp"
|
||||||
#include "rclcpp/qos.hpp"
|
#include "rclcpp/qos.hpp"
|
||||||
#include "rclcpp/qos_event.hpp"
|
#include "rclcpp/event_handler.hpp"
|
||||||
#include "rclcpp/qos_overriding_options.hpp"
|
#include "rclcpp/qos_overriding_options.hpp"
|
||||||
#include "rclcpp/subscription_content_filter_options.hpp"
|
#include "rclcpp/subscription_content_filter_options.hpp"
|
||||||
#include "rclcpp/topic_statistics_state.hpp"
|
#include "rclcpp/topic_statistics_state.hpp"
|
||||||
@@ -110,7 +110,6 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
|
|||||||
* \param qos QoS profile for subcription.
|
* \param qos QoS profile for subcription.
|
||||||
* \return rcl_subscription_options_t structure based on the rclcpp::QoS
|
* \return rcl_subscription_options_t structure based on the rclcpp::QoS
|
||||||
*/
|
*/
|
||||||
template<typename MessageT>
|
|
||||||
rcl_subscription_options_t
|
rcl_subscription_options_t
|
||||||
to_rcl_subscription_options(const rclcpp::QoS & qos) const
|
to_rcl_subscription_options(const rclcpp::QoS & qos) const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -149,11 +149,48 @@ public:
|
|||||||
bool
|
bool
|
||||||
exchange_in_use_by_wait_set_state(bool in_use_state);
|
exchange_in_use_by_wait_set_state(bool in_use_state);
|
||||||
|
|
||||||
|
/// Set a callback to be called when the timer is reset
|
||||||
|
/**
|
||||||
|
* You should aim to make this callback fast and not blocking.
|
||||||
|
* If you need to do a lot of work or wait for some other event, you should
|
||||||
|
* spin it off to another thread.
|
||||||
|
*
|
||||||
|
* Calling it again will override any previously set callback.
|
||||||
|
* An exception will be thrown if the callback is not callable.
|
||||||
|
*
|
||||||
|
* This function is thread-safe.
|
||||||
|
*
|
||||||
|
* If you want more information available in the callback,
|
||||||
|
* you may use a lambda with captures or std::bind.
|
||||||
|
*
|
||||||
|
* \param[in] callback functor to be called whenever timer is reset
|
||||||
|
*/
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_on_reset_callback(std::function<void(size_t)> callback);
|
||||||
|
|
||||||
|
/// Unset the callback registered for reset timer
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
clear_on_reset_callback();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
std::recursive_mutex callback_mutex_;
|
||||||
|
// Declare callback before timer_handle_, so on destruction
|
||||||
|
// the callback is destroyed last. Otherwise, the rcl timer
|
||||||
|
// callback would point briefly to a destroyed function.
|
||||||
|
// Clearing the callback on timer destructor also makes sure
|
||||||
|
// the rcl callback is cleared before on_reset_callback_.
|
||||||
|
std::function<void(size_t)> on_reset_callback_{nullptr};
|
||||||
|
|
||||||
Clock::SharedPtr clock_;
|
Clock::SharedPtr clock_;
|
||||||
std::shared_ptr<rcl_timer_t> timer_handle_;
|
std::shared_ptr<rcl_timer_t> timer_handle_;
|
||||||
|
|
||||||
std::atomic<bool> in_use_by_wait_set_{false};
|
std::atomic<bool> in_use_by_wait_set_{false};
|
||||||
|
|
||||||
|
RCLCPP_PUBLIC
|
||||||
|
void
|
||||||
|
set_on_reset_callback(rcl_event_callback_t callback, const void * user_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -190,10 +227,16 @@ public:
|
|||||||
rclcpp_timer_callback_added,
|
rclcpp_timer_callback_added,
|
||||||
static_cast<const void *>(get_timer_handle().get()),
|
static_cast<const void *>(get_timer_handle().get()),
|
||||||
reinterpret_cast<const void *>(&callback_));
|
reinterpret_cast<const void *>(&callback_));
|
||||||
TRACEPOINT(
|
#ifndef TRACETOOLS_DISABLED
|
||||||
rclcpp_callback_register,
|
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
|
||||||
reinterpret_cast<const void *>(&callback_),
|
char * symbol = tracetools::get_symbol(callback_);
|
||||||
tracetools::get_symbol(callback_));
|
DO_TRACEPOINT(
|
||||||
|
rclcpp_callback_register,
|
||||||
|
reinterpret_cast<const void *>(&callback_),
|
||||||
|
symbol);
|
||||||
|
std::free(symbol);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default destructor.
|
/// Default destructor.
|
||||||
|
|||||||
@@ -516,7 +516,7 @@ public:
|
|||||||
* the waitable to be removed, but it will cause the associated entity pointer
|
* the waitable to be removed, but it will cause the associated entity pointer
|
||||||
* to be nullptr when introspecting this waitable after waiting.
|
* to be nullptr when introspecting this waitable after waiting.
|
||||||
*
|
*
|
||||||
* Note that rclcpp::QOSEventHandlerBase are just a special case of
|
* Note that rclcpp::EventHandlerBase is just a special case of
|
||||||
* rclcpp::Waitable and can be added with this function.
|
* rclcpp::Waitable and can be added with this function.
|
||||||
*
|
*
|
||||||
* \param[in] waitable Waitable to be added.
|
* \param[in] waitable Waitable to be added.
|
||||||
|
|||||||
@@ -2,13 +2,17 @@
|
|||||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||||
<package format="2">
|
<package format="2">
|
||||||
<name>rclcpp</name>
|
<name>rclcpp</name>
|
||||||
<version>17.0.0</version>
|
<version>19.3.0</version>
|
||||||
<description>The ROS client library in C++.</description>
|
<description>The ROS client library in C++.</description>
|
||||||
|
|
||||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||||
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>
|
<maintainer email="michel@ekumenlabs.com">Michel Hidalgo</maintainer>
|
||||||
<maintainer email="william@openrobotics.org">William Woodall</maintainer>
|
<maintainer email="william@openrobotics.org">William Woodall</maintainer>
|
||||||
|
|
||||||
<license>Apache License 2.0</license>
|
<license>Apache License 2.0</license>
|
||||||
|
|
||||||
<author email="dthomas@openrobotics.org">Dirk Thomas</author>
|
<author email="dthomas@openrobotics.org">Dirk Thomas</author>
|
||||||
|
<author email="jacob@openrobotics.org">Jacob Perron</author>
|
||||||
|
|
||||||
<buildtool_depend>ament_cmake_ros</buildtool_depend>
|
<buildtool_depend>ament_cmake_ros</buildtool_depend>
|
||||||
<buildtool_depend>ament_cmake_gen_version_h</buildtool_depend>
|
<buildtool_depend>ament_cmake_gen_version_h</buildtool_depend>
|
||||||
@@ -35,6 +39,7 @@
|
|||||||
<depend>rcpputils</depend>
|
<depend>rcpputils</depend>
|
||||||
<depend>rcutils</depend>
|
<depend>rcutils</depend>
|
||||||
<depend>rmw</depend>
|
<depend>rmw</depend>
|
||||||
|
<depend>rosidl_dynamic_typesupport</depend>
|
||||||
<depend>statistics_msgs</depend>
|
<depend>statistics_msgs</depend>
|
||||||
<depend>tracetools</depend>
|
<depend>tracetools</depend>
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ def get_rclcpp_suffix_from_features(features):
|
|||||||
) \
|
) \
|
||||||
do { \
|
do { \
|
||||||
static_assert( \
|
static_assert( \
|
||||||
::std::is_same<typename std::remove_cv<typename std::remove_reference<decltype(logger)>::type>::type, \
|
::std::is_same<typename std::remove_cv_t<typename std::remove_reference_t<decltype(logger)>>, \
|
||||||
typename ::rclcpp::Logger>::value, \
|
typename ::rclcpp::Logger>::value, \
|
||||||
"First argument to logging macros must be an rclcpp::Logger"); \
|
"First argument to logging macros must be an rclcpp::Logger"); \
|
||||||
@[ if 'throttle' in feature_combination]@ \
|
@[ if 'throttle' in feature_combination]@ \
|
||||||
|
|||||||
@@ -12,9 +12,19 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#include "rclcpp/callback_group.hpp"
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <vector>
|
#include "rclcpp/callback_group.hpp"
|
||||||
|
#include "rclcpp/client.hpp"
|
||||||
|
#include "rclcpp/service.hpp"
|
||||||
|
#include "rclcpp/subscription_base.hpp"
|
||||||
|
#include "rclcpp/timer.hpp"
|
||||||
|
#include "rclcpp/waitable.hpp"
|
||||||
|
|
||||||
using rclcpp::CallbackGroup;
|
using rclcpp::CallbackGroup;
|
||||||
using rclcpp::CallbackGroupType;
|
using rclcpp::CallbackGroupType;
|
||||||
@@ -27,6 +37,10 @@ CallbackGroup::CallbackGroup(
|
|||||||
automatically_add_to_executor_with_node_(automatically_add_to_executor_with_node)
|
automatically_add_to_executor_with_node_(automatically_add_to_executor_with_node)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
CallbackGroup::~CallbackGroup()
|
||||||
|
{
|
||||||
|
trigger_notify_guard_condition();
|
||||||
|
}
|
||||||
|
|
||||||
std::atomic_bool &
|
std::atomic_bool &
|
||||||
CallbackGroup::can_be_taken_from()
|
CallbackGroup::can_be_taken_from()
|
||||||
@@ -97,6 +111,33 @@ CallbackGroup::automatically_add_to_executor_with_node() const
|
|||||||
return automatically_add_to_executor_with_node_;
|
return automatically_add_to_executor_with_node_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rclcpp::GuardCondition::SharedPtr
|
||||||
|
CallbackGroup::get_notify_guard_condition(const rclcpp::Context::SharedPtr context_ptr)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(notify_guard_condition_mutex_);
|
||||||
|
if (notify_guard_condition_ && context_ptr != notify_guard_condition_->get_context()) {
|
||||||
|
if (associated_with_executor_) {
|
||||||
|
trigger_notify_guard_condition();
|
||||||
|
}
|
||||||
|
notify_guard_condition_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notify_guard_condition_) {
|
||||||
|
notify_guard_condition_ = std::make_shared<rclcpp::GuardCondition>(context_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return notify_guard_condition_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CallbackGroup::trigger_notify_guard_condition()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(notify_guard_condition_mutex_);
|
||||||
|
if (notify_guard_condition_) {
|
||||||
|
notify_guard_condition_->trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CallbackGroup::add_subscription(
|
CallbackGroup::add_subscription(
|
||||||
const rclcpp::SubscriptionBase::SharedPtr subscription_ptr)
|
const rclcpp::SubscriptionBase::SharedPtr subscription_ptr)
|
||||||
|
|||||||
@@ -23,9 +23,11 @@
|
|||||||
#include "rcl/graph.h"
|
#include "rcl/graph.h"
|
||||||
#include "rcl/node.h"
|
#include "rcl/node.h"
|
||||||
#include "rcl/wait.h"
|
#include "rcl/wait.h"
|
||||||
|
|
||||||
#include "rclcpp/exceptions.hpp"
|
#include "rclcpp/exceptions.hpp"
|
||||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||||
|
#include "rclcpp/qos.hpp"
|
||||||
#include "rclcpp/utilities.hpp"
|
#include "rclcpp/utilities.hpp"
|
||||||
#include "rclcpp/logging.hpp"
|
#include "rclcpp/logging.hpp"
|
||||||
|
|
||||||
@@ -65,13 +67,6 @@ ClientBase::ClientBase(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientBase::~ClientBase()
|
|
||||||
{
|
|
||||||
clear_on_new_response_callback();
|
|
||||||
// Make sure the client handle is destructed as early as possible and before the node handle
|
|
||||||
client_handle_.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ClientBase::take_type_erased_response(void * response_out, rmw_request_id_t & request_header_out)
|
ClientBase::take_type_erased_response(void * response_out, rmw_request_id_t & request_header_out)
|
||||||
{
|
{
|
||||||
@@ -248,7 +243,6 @@ ClientBase::set_on_new_response_callback(rcl_event_callback_t callback, const vo
|
|||||||
user_data);
|
user_data);
|
||||||
|
|
||||||
if (RCL_RET_OK != ret) {
|
if (RCL_RET_OK != ret) {
|
||||||
using rclcpp::exceptions::throw_from_rcl_error;
|
|
||||||
throw_from_rcl_error(ret, "failed to set the on new response callback for client");
|
throw_from_rcl_error(ret, "failed to set the on new response callback for client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ Clock::Clock(rcl_clock_type_t clock_type)
|
|||||||
Clock::~Clock() {}
|
Clock::~Clock() {}
|
||||||
|
|
||||||
Time
|
Time
|
||||||
Clock::now()
|
Clock::now() const
|
||||||
{
|
{
|
||||||
Time now(0, 0, impl_->rcl_clock_.type);
|
Time now(0, 0, impl_->rcl_clock_.type);
|
||||||
|
|
||||||
@@ -182,6 +182,71 @@ Clock::sleep_for(Duration rel_time, Context::SharedPtr context)
|
|||||||
return sleep_until(now() + rel_time, context);
|
return sleep_until(now() + rel_time, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Clock::started()
|
||||||
|
{
|
||||||
|
if (!rcl_clock_valid(get_clock_handle())) {
|
||||||
|
throw std::runtime_error("clock is not rcl_clock_valid");
|
||||||
|
}
|
||||||
|
return rcl_clock_time_started(get_clock_handle());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Clock::wait_until_started(Context::SharedPtr context)
|
||||||
|
{
|
||||||
|
if (!context || !context->is_valid()) {
|
||||||
|
throw std::runtime_error("context cannot be slept with because it's invalid");
|
||||||
|
}
|
||||||
|
if (!rcl_clock_valid(get_clock_handle())) {
|
||||||
|
throw std::runtime_error("clock cannot be waited on as it is not rcl_clock_valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (started()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Wait until the first non-zero time
|
||||||
|
return sleep_until(rclcpp::Time(0, 1, get_clock_type()), context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Clock::wait_until_started(
|
||||||
|
const Duration & timeout,
|
||||||
|
Context::SharedPtr context,
|
||||||
|
const Duration & wait_tick_ns)
|
||||||
|
{
|
||||||
|
if (!context || !context->is_valid()) {
|
||||||
|
throw std::runtime_error("context cannot be slept with because it's invalid");
|
||||||
|
}
|
||||||
|
if (!rcl_clock_valid(get_clock_handle())) {
|
||||||
|
throw std::runtime_error("clock cannot be waited on as it is not rcl_clock_valid");
|
||||||
|
}
|
||||||
|
|
||||||
|
Clock timeout_clock = Clock(RCL_STEADY_TIME);
|
||||||
|
Time start = timeout_clock.now();
|
||||||
|
|
||||||
|
// Check if the clock has started every wait_tick_ns nanoseconds
|
||||||
|
// Context check checks for rclcpp::shutdown()
|
||||||
|
while (!started() && context->is_valid()) {
|
||||||
|
if (timeout < wait_tick_ns) {
|
||||||
|
timeout_clock.sleep_for(timeout);
|
||||||
|
} else {
|
||||||
|
Duration time_left = start + timeout - timeout_clock.now();
|
||||||
|
if (time_left > wait_tick_ns) {
|
||||||
|
timeout_clock.sleep_for(Duration(wait_tick_ns));
|
||||||
|
} else {
|
||||||
|
timeout_clock.sleep_for(time_left);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout_clock.now() - start > timeout) {
|
||||||
|
return started();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return started();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Clock::ros_time_is_active()
|
Clock::ros_time_is_active()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ Context::init(
|
|||||||
if (0u == count) {
|
if (0u == count) {
|
||||||
ret = rcl_logging_configure_with_output_handler(
|
ret = rcl_logging_configure_with_output_handler(
|
||||||
&rcl_context_->global_arguments,
|
&rcl_context_->global_arguments,
|
||||||
rcl_init_options_get_allocator(init_options_.get_rcl_init_options()),
|
rcl_init_options_get_allocator(init_options.get_rcl_init_options()),
|
||||||
rclcpp_logging_output_handler);
|
rclcpp_logging_output_handler);
|
||||||
if (RCL_RET_OK != ret) {
|
if (RCL_RET_OK != ret) {
|
||||||
rcl_context_.reset();
|
rcl_context_.reset();
|
||||||
@@ -365,49 +365,45 @@ Context::on_shutdown(OnShutdownCallback callback)
|
|||||||
rclcpp::OnShutdownCallbackHandle
|
rclcpp::OnShutdownCallbackHandle
|
||||||
Context::add_on_shutdown_callback(OnShutdownCallback callback)
|
Context::add_on_shutdown_callback(OnShutdownCallback callback)
|
||||||
{
|
{
|
||||||
return add_shutdown_callback(ShutdownType::on_shutdown, callback);
|
return add_shutdown_callback<ShutdownType::on_shutdown>(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Context::remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle)
|
Context::remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle)
|
||||||
{
|
{
|
||||||
return remove_shutdown_callback(ShutdownType::on_shutdown, callback_handle);
|
return remove_shutdown_callback<ShutdownType::on_shutdown>(callback_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
rclcpp::PreShutdownCallbackHandle
|
rclcpp::PreShutdownCallbackHandle
|
||||||
Context::add_pre_shutdown_callback(PreShutdownCallback callback)
|
Context::add_pre_shutdown_callback(PreShutdownCallback callback)
|
||||||
{
|
{
|
||||||
return add_shutdown_callback(ShutdownType::pre_shutdown, callback);
|
return add_shutdown_callback<ShutdownType::pre_shutdown>(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Context::remove_pre_shutdown_callback(
|
Context::remove_pre_shutdown_callback(
|
||||||
const PreShutdownCallbackHandle & callback_handle)
|
const PreShutdownCallbackHandle & callback_handle)
|
||||||
{
|
{
|
||||||
return remove_shutdown_callback(ShutdownType::pre_shutdown, callback_handle);
|
return remove_shutdown_callback<ShutdownType::pre_shutdown>(callback_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<Context::ShutdownType shutdown_type>
|
||||||
rclcpp::ShutdownCallbackHandle
|
rclcpp::ShutdownCallbackHandle
|
||||||
Context::add_shutdown_callback(
|
Context::add_shutdown_callback(
|
||||||
ShutdownType shutdown_type,
|
|
||||||
ShutdownCallback callback)
|
ShutdownCallback callback)
|
||||||
{
|
{
|
||||||
auto callback_shared_ptr =
|
auto callback_shared_ptr =
|
||||||
std::make_shared<ShutdownCallbackHandle::ShutdownCallbackType>(callback);
|
std::make_shared<ShutdownCallbackHandle::ShutdownCallbackType>(callback);
|
||||||
|
|
||||||
switch (shutdown_type) {
|
static_assert(
|
||||||
case ShutdownType::pre_shutdown:
|
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(pre_shutdown_callbacks_mutex_);
|
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||||
pre_shutdown_callbacks_.emplace(callback_shared_ptr);
|
std::lock_guard<std::mutex> lock(pre_shutdown_callbacks_mutex_);
|
||||||
}
|
pre_shutdown_callbacks_.emplace_back(callback_shared_ptr);
|
||||||
break;
|
} else {
|
||||||
case ShutdownType::on_shutdown:
|
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
|
||||||
{
|
on_shutdown_callbacks_.emplace_back(callback_shared_ptr);
|
||||||
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
|
|
||||||
on_shutdown_callbacks_.emplace(callback_shared_ptr);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ShutdownCallbackHandle callback_handle;
|
ShutdownCallbackHandle callback_handle;
|
||||||
@@ -415,73 +411,74 @@ Context::add_shutdown_callback(
|
|||||||
return callback_handle;
|
return callback_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<Context::ShutdownType shutdown_type>
|
||||||
bool
|
bool
|
||||||
Context::remove_shutdown_callback(
|
Context::remove_shutdown_callback(
|
||||||
ShutdownType shutdown_type,
|
|
||||||
const ShutdownCallbackHandle & callback_handle)
|
const ShutdownCallbackHandle & callback_handle)
|
||||||
{
|
{
|
||||||
std::mutex * mutex_ptr = nullptr;
|
const auto callback_shared_ptr = callback_handle.callback.lock();
|
||||||
std::unordered_set<
|
|
||||||
std::shared_ptr<ShutdownCallbackHandle::ShutdownCallbackType>> * callback_list_ptr;
|
|
||||||
|
|
||||||
switch (shutdown_type) {
|
|
||||||
case ShutdownType::pre_shutdown:
|
|
||||||
mutex_ptr = &pre_shutdown_callbacks_mutex_;
|
|
||||||
callback_list_ptr = &pre_shutdown_callbacks_;
|
|
||||||
break;
|
|
||||||
case ShutdownType::on_shutdown:
|
|
||||||
mutex_ptr = &on_shutdown_callbacks_mutex_;
|
|
||||||
callback_list_ptr = &on_shutdown_callbacks_;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(*mutex_ptr);
|
|
||||||
auto callback_shared_ptr = callback_handle.callback.lock();
|
|
||||||
if (callback_shared_ptr == nullptr) {
|
if (callback_shared_ptr == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return callback_list_ptr->erase(callback_shared_ptr) == 1;
|
|
||||||
|
const auto remove_callback = [&callback_shared_ptr](auto & mutex, auto & callback_vector) {
|
||||||
|
const std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
auto iter = callback_vector.begin();
|
||||||
|
for (; iter != callback_vector.end(); iter++) {
|
||||||
|
if ((*iter).get() == callback_shared_ptr.get()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iter == callback_vector.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
callback_vector.erase(iter);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||||
|
|
||||||
|
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||||
|
return remove_callback(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
|
||||||
|
} else {
|
||||||
|
return remove_callback(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<rclcpp::Context::OnShutdownCallback>
|
std::vector<rclcpp::Context::OnShutdownCallback>
|
||||||
Context::get_on_shutdown_callbacks() const
|
Context::get_on_shutdown_callbacks() const
|
||||||
{
|
{
|
||||||
return get_shutdown_callback(ShutdownType::on_shutdown);
|
return get_shutdown_callback<ShutdownType::on_shutdown>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<rclcpp::Context::PreShutdownCallback>
|
std::vector<rclcpp::Context::PreShutdownCallback>
|
||||||
Context::get_pre_shutdown_callbacks() const
|
Context::get_pre_shutdown_callbacks() const
|
||||||
{
|
{
|
||||||
return get_shutdown_callback(ShutdownType::pre_shutdown);
|
return get_shutdown_callback<ShutdownType::pre_shutdown>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<Context::ShutdownType shutdown_type>
|
||||||
std::vector<rclcpp::Context::ShutdownCallback>
|
std::vector<rclcpp::Context::ShutdownCallback>
|
||||||
Context::get_shutdown_callback(ShutdownType shutdown_type) const
|
Context::get_shutdown_callback() const
|
||||||
{
|
{
|
||||||
std::mutex * mutex_ptr = nullptr;
|
const auto get_callback_vector = [this](auto & mutex, auto & callback_set) {
|
||||||
const std::unordered_set<
|
const std::lock_guard<std::mutex> lock(mutex);
|
||||||
std::shared_ptr<ShutdownCallbackHandle::ShutdownCallbackType>> * callback_list_ptr;
|
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
|
||||||
|
for (auto & callback : callback_set) {
|
||||||
|
callbacks.push_back(*callback);
|
||||||
|
}
|
||||||
|
return callbacks;
|
||||||
|
};
|
||||||
|
|
||||||
switch (shutdown_type) {
|
static_assert(
|
||||||
case ShutdownType::pre_shutdown:
|
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||||
mutex_ptr = &pre_shutdown_callbacks_mutex_;
|
|
||||||
callback_list_ptr = &pre_shutdown_callbacks_;
|
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||||
break;
|
return get_callback_vector(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
|
||||||
case ShutdownType::on_shutdown:
|
} else {
|
||||||
mutex_ptr = &on_shutdown_callbacks_mutex_;
|
return get_callback_vector(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
|
||||||
callback_list_ptr = &on_shutdown_callbacks_;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(*mutex_ptr);
|
|
||||||
for (auto & iter : *callback_list_ptr) {
|
|
||||||
callbacks.emplace_back(*iter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return callbacks;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<rcl_context_t>
|
std::shared_ptr<rcl_context_t>
|
||||||
|
|||||||
113
rclcpp/src/rclcpp/dynamic_subscription.cpp
Normal file
113
rclcpp/src/rclcpp/dynamic_subscription.cpp
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_subscription.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rcl/subscription.h"
|
||||||
|
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
|
||||||
|
namespace rclcpp
|
||||||
|
{
|
||||||
|
|
||||||
|
std::shared_ptr<void> DynamicSubscription::create_message()
|
||||||
|
{
|
||||||
|
return create_serialized_message();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<rclcpp::SerializedMessage> DynamicSubscription::create_serialized_message()
|
||||||
|
{
|
||||||
|
return std::make_shared<rclcpp::SerializedMessage>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicSubscription::handle_message(std::shared_ptr<void> &, const rclcpp::MessageInfo &)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"handle_message is not implemented for DynamicSubscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicSubscription::handle_serialized_message(
|
||||||
|
const std::shared_ptr<rclcpp::SerializedMessage> &, const rclcpp::MessageInfo &)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"handle_serialized_message is not implemented for DynamicSubscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicSubscription::handle_loaned_message(void *, const rclcpp::MessageInfo &)
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"handle_loaned_message is not implemented for DynamicSubscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicSubscription::return_message(std::shared_ptr<void> & message)
|
||||||
|
{
|
||||||
|
auto typed_message = std::static_pointer_cast<rclcpp::SerializedMessage>(message);
|
||||||
|
return_serialized_message(typed_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicSubscription::return_serialized_message(
|
||||||
|
std::shared_ptr<rclcpp::SerializedMessage> & message)
|
||||||
|
{
|
||||||
|
message.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DYNAMIC TYPE ====================================================================================
|
||||||
|
// TODO(methylDragon): Re-order later
|
||||||
|
|
||||||
|
// Does not clone
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
|
||||||
|
DynamicSubscription::get_shared_dynamic_message_type()
|
||||||
|
{
|
||||||
|
return dynamic_message_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does not clone
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
|
||||||
|
DynamicSubscription::get_shared_dynamic_message()
|
||||||
|
{
|
||||||
|
return dynamic_message_;
|
||||||
|
}
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
|
||||||
|
DynamicSubscription::get_shared_dynamic_serialization_support()
|
||||||
|
{
|
||||||
|
return serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
|
||||||
|
DynamicSubscription::create_dynamic_message()
|
||||||
|
{
|
||||||
|
return dynamic_message_->init_from_type_shared(*dynamic_message_type_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicSubscription::return_dynamic_message(
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
|
||||||
|
{
|
||||||
|
message.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicSubscription::handle_dynamic_message(
|
||||||
|
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
|
||||||
|
const rclcpp::MessageInfo & message_info)
|
||||||
|
{
|
||||||
|
(void) message_info;
|
||||||
|
callback_(message, ts_->get_rosidl_runtime_c_type_description());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace rclcpp
|
||||||
769
rclcpp/src/rclcpp/dynamic_typesupport/dynamic_message.cpp
Normal file
769
rclcpp/src/rclcpp/dynamic_typesupport/dynamic_message.cpp
Normal file
@@ -0,0 +1,769 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/serialization_support.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rcl/allocator.h"
|
||||||
|
#include "rcl/types.h"
|
||||||
|
#include "rcutils/logging_macros.h"
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessage;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessageType;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
|
||||||
|
// Template specialization implementations
|
||||||
|
#include "rclcpp/dynamic_typesupport/detail/dynamic_message_impl.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// CONSTRUCTION ==================================================================================
|
||||||
|
DynamicMessage::DynamicMessage(const DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder)
|
||||||
|
: DynamicMessage::DynamicMessage(
|
||||||
|
dynamic_type_builder, dynamic_type_builder->get_rosidl_dynamic_type_builder().allocator) {}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::DynamicMessage(
|
||||||
|
const DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: serialization_support_(dynamic_type_builder->get_shared_dynamic_serialization_support()),
|
||||||
|
rosidl_dynamic_data_(rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data()),
|
||||||
|
is_loaned_(false),
|
||||||
|
parent_data_(nullptr)
|
||||||
|
{
|
||||||
|
if (!serialization_support_) {
|
||||||
|
throw std::runtime_error("dynamic message could not bind serialization support!");
|
||||||
|
}
|
||||||
|
if (!dynamic_type_builder) {
|
||||||
|
throw std::runtime_error("dynamic message type builder cannot be nullptr!");
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
|
||||||
|
dynamic_type_builder->get_rosidl_dynamic_type_builder();
|
||||||
|
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_init_from_dynamic_type_builder(
|
||||||
|
&rosidl_dynamic_type_builder, &allocator, &get_rosidl_dynamic_data());
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not init new dynamic data object from dynamic type builder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::DynamicMessage(const DynamicMessageType::SharedPtr dynamic_type)
|
||||||
|
: DynamicMessage::DynamicMessage(
|
||||||
|
dynamic_type, dynamic_type->get_rosidl_dynamic_type().allocator) {}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::DynamicMessage(
|
||||||
|
const DynamicMessageType::SharedPtr dynamic_type,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: serialization_support_(dynamic_type->get_shared_dynamic_serialization_support()),
|
||||||
|
rosidl_dynamic_data_(rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data()),
|
||||||
|
is_loaned_(false),
|
||||||
|
parent_data_(nullptr)
|
||||||
|
{
|
||||||
|
if (!serialization_support_) {
|
||||||
|
throw std::runtime_error("dynamic type could not bind serialization support!");
|
||||||
|
}
|
||||||
|
if (!dynamic_type) {
|
||||||
|
throw std::runtime_error("dynamic message type cannot be nullptr!");
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type =
|
||||||
|
dynamic_type->get_rosidl_dynamic_type();
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_init_from_dynamic_type(
|
||||||
|
&rosidl_dynamic_type, &allocator, &rosidl_dynamic_data);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not init new dynamic data object from dynamic type") +
|
||||||
|
rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::DynamicMessage(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_dynamic_data)
|
||||||
|
: serialization_support_(serialization_support),
|
||||||
|
rosidl_dynamic_data_(std::move(rosidl_dynamic_data)),
|
||||||
|
is_loaned_(false),
|
||||||
|
parent_data_(nullptr)
|
||||||
|
{
|
||||||
|
if (serialization_support) {
|
||||||
|
if (!match_serialization_support_(*serialization_support, rosidl_dynamic_data)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"serialization support library identifier does not match dynamic data's!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::DynamicMessage(
|
||||||
|
DynamicMessage::SharedPtr parent_data,
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_loaned_data)
|
||||||
|
: serialization_support_(parent_data->get_shared_dynamic_serialization_support()),
|
||||||
|
rosidl_dynamic_data_(std::move(rosidl_loaned_data)),
|
||||||
|
is_loaned_(true),
|
||||||
|
parent_data_(nullptr)
|
||||||
|
{
|
||||||
|
if (!parent_data) {
|
||||||
|
throw std::runtime_error("parent dynamic data cannot be nullptr!");
|
||||||
|
}
|
||||||
|
if (serialization_support_) {
|
||||||
|
if (!match_serialization_support_(*serialization_support_, rosidl_loaned_data)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"serialization support library identifier does not match loaned dynamic data's!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent_data_ = parent_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::DynamicMessage(DynamicMessage && other) noexcept
|
||||||
|
: serialization_support_(std::exchange(other.serialization_support_, nullptr)),
|
||||||
|
rosidl_dynamic_data_(std::exchange(
|
||||||
|
other.rosidl_dynamic_data_,
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data())),
|
||||||
|
is_loaned_(other.is_loaned_),
|
||||||
|
parent_data_(std::exchange(other.parent_data_, nullptr))
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage &
|
||||||
|
DynamicMessage::operator=(DynamicMessage && other) noexcept
|
||||||
|
{
|
||||||
|
std::swap(serialization_support_, other.serialization_support_);
|
||||||
|
std::swap(rosidl_dynamic_data_, other.rosidl_dynamic_data_);
|
||||||
|
is_loaned_ = other.is_loaned_;
|
||||||
|
std::swap(parent_data_, other.parent_data_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::~DynamicMessage()
|
||||||
|
{
|
||||||
|
if (!is_loaned_) {
|
||||||
|
if (rosidl_dynamic_typesupport_dynamic_data_fini(&get_rosidl_dynamic_data()) !=
|
||||||
|
RCUTILS_RET_OK)
|
||||||
|
{
|
||||||
|
RCUTILS_LOG_ERROR("could not fini rosidl dynamic data");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loaned case
|
||||||
|
if (!parent_data_) {
|
||||||
|
RCUTILS_LOG_ERROR("dynamic data is loaned, but parent is missing!!");
|
||||||
|
} else {
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_return_loaned_value(
|
||||||
|
&parent_data_->get_rosidl_dynamic_data(), &get_rosidl_dynamic_data());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DynamicMessage::match_serialization_support_(
|
||||||
|
const DynamicSerializationSupport & serialization_support,
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_data_t & rosidl_dynamic_type_data)
|
||||||
|
{
|
||||||
|
if (serialization_support.get_serialization_library_identifier() != std::string(
|
||||||
|
rosidl_dynamic_type_data.serialization_support->serialization_library_identifier))
|
||||||
|
{
|
||||||
|
RCUTILS_LOG_ERROR("serialization support library identifier does not match dynamic data's");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GETTERS =======================================================================================
|
||||||
|
const std::string
|
||||||
|
DynamicMessage::get_serialization_library_identifier() const
|
||||||
|
{
|
||||||
|
return std::string(
|
||||||
|
get_rosidl_dynamic_data().serialization_support->serialization_library_identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::string
|
||||||
|
DynamicMessage::get_name() const
|
||||||
|
{
|
||||||
|
size_t buf_length;
|
||||||
|
const char * buf;
|
||||||
|
if (
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_name(
|
||||||
|
&get_rosidl_dynamic_data(), &buf,
|
||||||
|
&buf_length) !=
|
||||||
|
RCUTILS_RET_OK)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not get name for dynamic data") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return std::string(buf, buf_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t &
|
||||||
|
DynamicMessage::get_rosidl_dynamic_data()
|
||||||
|
{
|
||||||
|
return rosidl_dynamic_data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_data_t &
|
||||||
|
DynamicMessage::get_rosidl_dynamic_data() const
|
||||||
|
{
|
||||||
|
return rosidl_dynamic_data_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicSerializationSupport::SharedPtr
|
||||||
|
DynamicMessage::get_shared_dynamic_serialization_support()
|
||||||
|
{
|
||||||
|
return serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicSerializationSupport::ConstSharedPtr
|
||||||
|
DynamicMessage::get_shared_dynamic_serialization_support() const
|
||||||
|
{
|
||||||
|
return serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
DynamicMessage::get_item_count() const
|
||||||
|
{
|
||||||
|
size_t item_count;
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_item_count(
|
||||||
|
&get_rosidl_dynamic_data(), &item_count);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not get item count of dynamic data");
|
||||||
|
}
|
||||||
|
return item_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::get_member_id(size_t index) const
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t member_id;
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_member_id_at_index(
|
||||||
|
&get_rosidl_dynamic_data(), index, &member_id);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not member id of dynamic data element by index");
|
||||||
|
}
|
||||||
|
return member_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::get_member_id(const std::string & name) const
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t member_id;
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_member_id_by_name(
|
||||||
|
&get_rosidl_dynamic_data(), name.c_str(), name.size(), &member_id);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not member id of dynamic data element by name");
|
||||||
|
}
|
||||||
|
return member_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::get_array_index(size_t index) const
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t array_index;
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_array_index(
|
||||||
|
&get_rosidl_dynamic_data(), index, &array_index);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not array index of dynamic data element by index");
|
||||||
|
}
|
||||||
|
return array_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::get_array_index(const std::string & name) const
|
||||||
|
{
|
||||||
|
return get_array_index(get_member_id(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// METHODS =======================================================================================
|
||||||
|
DynamicMessage
|
||||||
|
DynamicMessage::clone(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_clone(
|
||||||
|
&get_rosidl_dynamic_data(), &allocator, &rosidl_dynamic_data);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not clone dynamic data: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return DynamicMessage(get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
DynamicMessage::clone_shared(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_clone(
|
||||||
|
&get_rosidl_dynamic_data(), &allocator, &rosidl_dynamic_data);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not clone dynamic data: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return DynamicMessage::make_shared(
|
||||||
|
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage
|
||||||
|
DynamicMessage::init_from_type(DynamicMessageType & type, rcl_allocator_t allocator) const
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_init_from_dynamic_type(
|
||||||
|
&type.get_rosidl_dynamic_type(), &allocator, &rosidl_dynamic_data);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not init new dynamic data object from dynamic type");
|
||||||
|
}
|
||||||
|
return DynamicMessage(serialization_support_, std::move(rosidl_dynamic_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
DynamicMessage::init_from_type_shared(DynamicMessageType & type, rcl_allocator_t allocator) const
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_init_from_dynamic_type(
|
||||||
|
&type.get_rosidl_dynamic_type(), &allocator, &rosidl_dynamic_data);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not init new dynamic data object from dynamic type");
|
||||||
|
}
|
||||||
|
return DynamicMessage::make_shared(serialization_support_, std::move(rosidl_dynamic_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DynamicMessage::equals(const DynamicMessage & other) const
|
||||||
|
{
|
||||||
|
if (get_serialization_library_identifier() != other.get_serialization_library_identifier()) {
|
||||||
|
throw std::runtime_error("library identifiers don't match");
|
||||||
|
}
|
||||||
|
bool equals;
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_equals(
|
||||||
|
&get_rosidl_dynamic_data(), &other.get_rosidl_dynamic_data(), &equals);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not equate dynamic messages");
|
||||||
|
}
|
||||||
|
return equals;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
DynamicMessage::loan_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_loan_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &allocator, &rosidl_dynamic_data);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not loan dynamic data: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return DynamicMessage::make_shared(shared_from_this(), std::move(rosidl_dynamic_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
DynamicMessage::loan_value(const std::string & name, rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
return loan_value(get_member_id(name), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::clear_all_values()
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_clear_all_values(&get_rosidl_dynamic_data());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::clear_nonkey_values()
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_clear_nonkey_values(&get_rosidl_dynamic_data());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::clear_value(rosidl_dynamic_typesupport_member_id_t id)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_clear_value(&get_rosidl_dynamic_data(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::clear_value(const std::string & name)
|
||||||
|
{
|
||||||
|
clear_value(get_member_id(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::clear_sequence()
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_clear_sequence_data(&get_rosidl_dynamic_data());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_sequence_data()
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_sequence_data(&get_rosidl_dynamic_data(), &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::remove_sequence_data(rosidl_dynamic_typesupport_member_id_t index)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_remove_sequence_data(
|
||||||
|
&get_rosidl_dynamic_data(), index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DynamicMessage::serialize(rcl_serialized_message_t & buffer)
|
||||||
|
{
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_serialize(
|
||||||
|
&get_rosidl_dynamic_data(), &buffer);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could serialize loan dynamic data: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DynamicMessage::deserialize(rcl_serialized_message_t & buffer)
|
||||||
|
{
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_deserialize(
|
||||||
|
&get_rosidl_dynamic_data(), &buffer);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could deserialize loan dynamic data: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MEMBER ACCESS ===================================================================================
|
||||||
|
// Defined in "detail/dynamic_message_impl.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// FIXED STRING MEMBER ACCESS ======================================================================
|
||||||
|
const std::string
|
||||||
|
DynamicMessage::get_fixed_string_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, size_t string_length)
|
||||||
|
{
|
||||||
|
size_t buf_length;
|
||||||
|
char * buf = nullptr;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_fixed_string_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &buf, &buf_length, string_length);
|
||||||
|
auto out = std::string(buf, buf_length);
|
||||||
|
delete buf;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::string
|
||||||
|
DynamicMessage::get_fixed_string_value(const std::string & name, size_t string_length)
|
||||||
|
{
|
||||||
|
return get_fixed_string_value(get_member_id(name), string_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::u16string
|
||||||
|
DynamicMessage::get_fixed_wstring_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, size_t wstring_length)
|
||||||
|
{
|
||||||
|
size_t buf_length;
|
||||||
|
char16_t * buf = nullptr;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_fixed_wstring_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &buf, &buf_length, wstring_length);
|
||||||
|
auto out = std::u16string(buf, buf_length);
|
||||||
|
delete buf;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::u16string
|
||||||
|
DynamicMessage::get_fixed_wstring_value(const std::string & name, size_t wstring_length)
|
||||||
|
{
|
||||||
|
return get_fixed_wstring_value(get_member_id(name), wstring_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_fixed_string_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_length)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_set_fixed_string_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, value.c_str(), value.size(), string_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_fixed_string_value(
|
||||||
|
const std::string & name, const std::string value, size_t string_length)
|
||||||
|
{
|
||||||
|
set_fixed_string_value(get_member_id(name), value, string_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_fixed_wstring_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_length)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_set_fixed_wstring_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, value.c_str(), value.size(), wstring_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_fixed_wstring_value(
|
||||||
|
const std::string & name, const std::u16string value, size_t wstring_length)
|
||||||
|
{
|
||||||
|
set_fixed_wstring_value(get_member_id(name), value, wstring_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_fixed_string_value(const std::string value, size_t string_length)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_fixed_string_value(
|
||||||
|
&get_rosidl_dynamic_data(), value.c_str(), value.size(), string_length, &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_fixed_wstring_value(const std::u16string value, size_t wstring_length)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_fixed_wstring_value(
|
||||||
|
&get_rosidl_dynamic_data(), value.c_str(), value.size(), wstring_length, &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// BOUNDED STRING MEMBER ACCESS ====================================================================
|
||||||
|
const std::string
|
||||||
|
DynamicMessage::get_bounded_string_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, size_t string_bound)
|
||||||
|
{
|
||||||
|
size_t buf_length;
|
||||||
|
char * buf = nullptr;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_bounded_string_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &buf, &buf_length, string_bound);
|
||||||
|
auto out = std::string(buf, buf_length);
|
||||||
|
delete buf;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::string
|
||||||
|
DynamicMessage::get_bounded_string_value(const std::string & name, size_t string_bound)
|
||||||
|
{
|
||||||
|
return get_bounded_string_value(get_member_id(name), string_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::u16string
|
||||||
|
DynamicMessage::get_bounded_wstring_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, size_t wstring_bound)
|
||||||
|
{
|
||||||
|
size_t buf_length;
|
||||||
|
char16_t * buf = nullptr;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_bounded_wstring_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &buf, &buf_length, wstring_bound);
|
||||||
|
auto out = std::u16string(buf, buf_length);
|
||||||
|
delete buf;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::u16string
|
||||||
|
DynamicMessage::get_bounded_wstring_value(const std::string & name, size_t wstring_bound)
|
||||||
|
{
|
||||||
|
return get_bounded_wstring_value(get_member_id(name), wstring_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_bounded_string_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_bound)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_set_bounded_string_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, value.c_str(), value.size(), string_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_bounded_string_value(
|
||||||
|
const std::string & name, const std::string value, size_t string_bound)
|
||||||
|
{
|
||||||
|
set_bounded_string_value(get_member_id(name), value, string_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_bounded_wstring_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_bound)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_set_bounded_wstring_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, value.c_str(), value.size(), wstring_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_bounded_wstring_value(
|
||||||
|
const std::string & name, const std::u16string value, size_t wstring_bound)
|
||||||
|
{
|
||||||
|
set_bounded_wstring_value(get_member_id(name), value, wstring_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_bounded_string_value(const std::string value, size_t string_bound)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_bounded_string_value(
|
||||||
|
&get_rosidl_dynamic_data(), value.c_str(), value.size(), string_bound, &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_bounded_wstring_value(const std::u16string value, size_t wstring_bound)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_bounded_wstring_value(
|
||||||
|
&get_rosidl_dynamic_data(), value.c_str(), value.size(), wstring_bound, &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NESTED MEMBER ACCESS ============================================================================
|
||||||
|
DynamicMessage
|
||||||
|
DynamicMessage::get_complex_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t out =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_complex_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &allocator, &out);
|
||||||
|
return DynamicMessage(get_shared_dynamic_serialization_support(), std::move(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage
|
||||||
|
DynamicMessage::get_complex_value(const std::string & name, rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
return get_complex_value(get_member_id(name), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
DynamicMessage::get_complex_value_shared(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_t out =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_data();
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_get_complex_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &allocator, &out);
|
||||||
|
return DynamicMessage::make_shared(get_shared_dynamic_serialization_support(), std::move(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
DynamicMessage::get_complex_value_shared(const std::string & name, rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
return get_complex_value_shared(get_member_id(name), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_complex_value(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, DynamicMessage & value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_set_complex_value(
|
||||||
|
&get_rosidl_dynamic_data(), id, &value.get_rosidl_dynamic_data());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessage::set_complex_value(const std::string & name, DynamicMessage & value)
|
||||||
|
{
|
||||||
|
set_complex_value(get_member_id(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_complex_value_copy(const DynamicMessage & value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_complex_value_copy(
|
||||||
|
&get_rosidl_dynamic_data(), &value.get_rosidl_dynamic_data(), &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_member_id_t
|
||||||
|
DynamicMessage::insert_complex_value(DynamicMessage & value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_member_id_t out;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_data_insert_complex_value(
|
||||||
|
&get_rosidl_dynamic_data(), &value.get_rosidl_dynamic_data(), &out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
281
rclcpp/src/rclcpp/dynamic_typesupport/dynamic_message_type.cpp
Normal file
281
rclcpp/src/rclcpp/dynamic_typesupport/dynamic_message_type.cpp
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/serialization_support.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rcutils/logging_macros.h"
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessage;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessageType;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
|
||||||
|
|
||||||
|
|
||||||
|
// CONSTRUCTION ====================================================================================
|
||||||
|
DynamicMessageType::DynamicMessageType(DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder)
|
||||||
|
: DynamicMessageType::DynamicMessageType(
|
||||||
|
dynamic_type_builder, dynamic_type_builder->get_rosidl_dynamic_type_builder().allocator) {}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageType::DynamicMessageType(
|
||||||
|
DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: serialization_support_(dynamic_type_builder->get_shared_dynamic_serialization_support()),
|
||||||
|
rosidl_dynamic_type_(rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type())
|
||||||
|
{
|
||||||
|
if (!serialization_support_) {
|
||||||
|
throw std::runtime_error("dynamic type could not bind serialization support!");
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
|
||||||
|
dynamic_type_builder->get_rosidl_dynamic_type_builder();
|
||||||
|
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_init_from_dynamic_type_builder(
|
||||||
|
&rosidl_dynamic_type_builder, &allocator, &get_rosidl_dynamic_type());
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not init new dynamic type object");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageType::DynamicMessageType(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_t && rosidl_dynamic_type)
|
||||||
|
: serialization_support_(serialization_support),
|
||||||
|
rosidl_dynamic_type_(std::move(rosidl_dynamic_type))
|
||||||
|
{
|
||||||
|
if (serialization_support) {
|
||||||
|
if (!match_serialization_support_(*serialization_support, rosidl_dynamic_type)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"serialization support library identifier does not match dynamic type's!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageType::DynamicMessageType(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: serialization_support_(serialization_support),
|
||||||
|
rosidl_dynamic_type_(rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type())
|
||||||
|
{
|
||||||
|
init_from_description(description, allocator, serialization_support);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageType::DynamicMessageType(DynamicMessageType && other) noexcept
|
||||||
|
: serialization_support_(std::exchange(other.serialization_support_, nullptr)),
|
||||||
|
rosidl_dynamic_type_(std::exchange(
|
||||||
|
other.rosidl_dynamic_type_, rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type()))
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageType &
|
||||||
|
DynamicMessageType::operator=(DynamicMessageType && other) noexcept
|
||||||
|
{
|
||||||
|
std::swap(serialization_support_, other.serialization_support_);
|
||||||
|
std::swap(rosidl_dynamic_type_, other.rosidl_dynamic_type_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageType::~DynamicMessageType()
|
||||||
|
{
|
||||||
|
if (rosidl_dynamic_typesupport_dynamic_type_fini(&get_rosidl_dynamic_type()) != RCUTILS_RET_OK) {
|
||||||
|
RCUTILS_LOG_ERROR("could not fini rosidl dynamic type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageType::init_from_description(
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support)
|
||||||
|
{
|
||||||
|
if (serialization_support) {
|
||||||
|
// Swap serialization support if serialization support is given
|
||||||
|
serialization_support_ = serialization_support;
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_init_from_description(
|
||||||
|
&serialization_support_->get_rosidl_serialization_support(),
|
||||||
|
&description,
|
||||||
|
&allocator,
|
||||||
|
&rosidl_dynamic_type);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not init new dynamic type object");
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_dynamic_type_ = std::move(rosidl_dynamic_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DynamicMessageType::match_serialization_support_(
|
||||||
|
const DynamicSerializationSupport & serialization_support,
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_type_t & rosidl_dynamic_type)
|
||||||
|
{
|
||||||
|
if (serialization_support.get_serialization_library_identifier() != std::string(
|
||||||
|
rosidl_dynamic_type.serialization_support->serialization_library_identifier))
|
||||||
|
{
|
||||||
|
RCUTILS_LOG_ERROR(
|
||||||
|
"serialization support library identifier does not match dynamic type's (%s vs %s)",
|
||||||
|
serialization_support.get_serialization_library_identifier().c_str(),
|
||||||
|
rosidl_dynamic_type.serialization_support->serialization_library_identifier);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GETTERS =========================================================================================
|
||||||
|
const std::string
|
||||||
|
DynamicMessageType::get_serialization_library_identifier() const
|
||||||
|
{
|
||||||
|
return std::string(
|
||||||
|
get_rosidl_dynamic_type().serialization_support->serialization_library_identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::string
|
||||||
|
DynamicMessageType::get_name() const
|
||||||
|
{
|
||||||
|
size_t buf_length;
|
||||||
|
const char * buf;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_get_name(&get_rosidl_dynamic_type(), &buf, &buf_length);
|
||||||
|
return std::string(buf, buf_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
DynamicMessageType::get_member_count() const
|
||||||
|
{
|
||||||
|
size_t out;
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_get_member_count(
|
||||||
|
&get_rosidl_dynamic_type(), &out);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not get member count: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_t &
|
||||||
|
DynamicMessageType::get_rosidl_dynamic_type()
|
||||||
|
{
|
||||||
|
return rosidl_dynamic_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_type_t &
|
||||||
|
DynamicMessageType::get_rosidl_dynamic_type() const
|
||||||
|
{
|
||||||
|
return rosidl_dynamic_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicSerializationSupport::SharedPtr
|
||||||
|
DynamicMessageType::get_shared_dynamic_serialization_support()
|
||||||
|
{
|
||||||
|
return serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicSerializationSupport::ConstSharedPtr
|
||||||
|
DynamicMessageType::get_shared_dynamic_serialization_support() const
|
||||||
|
{
|
||||||
|
return serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// METHODS =========================================================================================
|
||||||
|
DynamicMessageType
|
||||||
|
DynamicMessageType::clone(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_clone(
|
||||||
|
&get_rosidl_dynamic_type(), &allocator, &rosidl_dynamic_type);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not clone dynamic type: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return DynamicMessageType(
|
||||||
|
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageType::SharedPtr
|
||||||
|
DynamicMessageType::clone_shared(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_clone(
|
||||||
|
&get_rosidl_dynamic_type(), &allocator, &rosidl_dynamic_type);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not clone dynamic type: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return DynamicMessageType::make_shared(
|
||||||
|
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DynamicMessageType::equals(const DynamicMessageType & other) const
|
||||||
|
{
|
||||||
|
if (get_serialization_library_identifier() != other.get_serialization_library_identifier()) {
|
||||||
|
throw std::runtime_error("library identifiers don't match");
|
||||||
|
}
|
||||||
|
bool out;
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_equals(
|
||||||
|
&get_rosidl_dynamic_type(), &other.get_rosidl_dynamic_type(), &out);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not equate dynamic message types: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage
|
||||||
|
DynamicMessageType::build_dynamic_message(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
return DynamicMessage(shared_from_this(), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
DynamicMessageType::build_dynamic_message_shared(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
return DynamicMessage::make_shared(shared_from_this(), allocator);
|
||||||
|
}
|
||||||
@@ -0,0 +1,614 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/serialization_support.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rcutils/logging_macros.h"
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessage;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessageType;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
|
||||||
|
|
||||||
|
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
|
||||||
|
// Template specialization implementations
|
||||||
|
#include "rclcpp/dynamic_typesupport/detail/dynamic_message_type_builder_impl.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CONSTRUCTION ====================================================================================
|
||||||
|
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support, const std::string & name)
|
||||||
|
: DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
|
||||||
|
serialization_support,
|
||||||
|
name,
|
||||||
|
serialization_support->get_rosidl_serialization_support().allocator) {}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const std::string & name,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: serialization_support_(serialization_support),
|
||||||
|
rosidl_dynamic_type_builder_(
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder())
|
||||||
|
{
|
||||||
|
init_from_serialization_support_(serialization_support, name, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t && rosidl_dynamic_type_builder)
|
||||||
|
: serialization_support_(serialization_support),
|
||||||
|
rosidl_dynamic_type_builder_(
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder())
|
||||||
|
{
|
||||||
|
if (!serialization_support) {
|
||||||
|
throw std::runtime_error("serialization support cannot be nullptr!");
|
||||||
|
}
|
||||||
|
if (!match_serialization_support_(*serialization_support, rosidl_dynamic_type_builder)) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"serialization support library does not match dynamic type builder's!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: serialization_support_(serialization_support),
|
||||||
|
rosidl_dynamic_type_builder_(
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder())
|
||||||
|
{
|
||||||
|
if (!serialization_support) {
|
||||||
|
throw std::runtime_error("serialization support cannot be nullptr!");
|
||||||
|
}
|
||||||
|
init_from_description(description, allocator, serialization_support);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(DynamicMessageTypeBuilder && other) noexcept
|
||||||
|
: serialization_support_(std::exchange(other.serialization_support_, nullptr)),
|
||||||
|
rosidl_dynamic_type_builder_(std::exchange(
|
||||||
|
other.rosidl_dynamic_type_builder_,
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder())) {}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageTypeBuilder &
|
||||||
|
DynamicMessageTypeBuilder::operator=(DynamicMessageTypeBuilder && other) noexcept
|
||||||
|
{
|
||||||
|
std::swap(serialization_support_, other.serialization_support_);
|
||||||
|
std::swap(rosidl_dynamic_type_builder_, other.rosidl_dynamic_type_builder_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageTypeBuilder::~DynamicMessageTypeBuilder()
|
||||||
|
{
|
||||||
|
if (rosidl_dynamic_typesupport_dynamic_type_builder_fini(&get_rosidl_dynamic_type_builder()) !=
|
||||||
|
RCUTILS_RET_OK)
|
||||||
|
{
|
||||||
|
RCUTILS_LOG_ERROR("could not fini rosidl dynamic type builder");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::init_from_description(
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator,
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support)
|
||||||
|
{
|
||||||
|
if (serialization_support) {
|
||||||
|
// Swap serialization support if serialization support is given
|
||||||
|
serialization_support_ = serialization_support;
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_init_from_description(
|
||||||
|
&serialization_support_->get_rosidl_serialization_support(),
|
||||||
|
&description,
|
||||||
|
&allocator,
|
||||||
|
&rosidl_dynamic_type_builder);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not init new dynamic type builder object");
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_dynamic_type_builder_ = std::move(rosidl_dynamic_type_builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::init_from_serialization_support_(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const std::string & name,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
if (!serialization_support) {
|
||||||
|
throw std::runtime_error("serialization support cannot be nullptr!");
|
||||||
|
}
|
||||||
|
if (!&serialization_support->get_rosidl_serialization_support()) {
|
||||||
|
throw std::runtime_error("serialization support raw pointer cannot be nullptr!");
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_init(
|
||||||
|
&serialization_support->get_rosidl_serialization_support(),
|
||||||
|
name.c_str(), name.size(),
|
||||||
|
&allocator,
|
||||||
|
&rosidl_dynamic_type_builder);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not init dynamic type builder: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DynamicMessageTypeBuilder::match_serialization_support_(
|
||||||
|
const DynamicSerializationSupport & serialization_support,
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_type_builder_t & rosidl_dynamic_type_builder)
|
||||||
|
{
|
||||||
|
if (serialization_support.get_serialization_library_identifier() != std::string(
|
||||||
|
rosidl_dynamic_type_builder.serialization_support->serialization_library_identifier))
|
||||||
|
{
|
||||||
|
RCUTILS_LOG_ERROR(
|
||||||
|
"serialization support library identifier does not match dynamic type builder's");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GETTERS =======================================================================================
|
||||||
|
const std::string
|
||||||
|
DynamicMessageTypeBuilder::get_serialization_library_identifier() const
|
||||||
|
{
|
||||||
|
return std::string(
|
||||||
|
get_rosidl_dynamic_type_builder().serialization_support->serialization_library_identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const std::string
|
||||||
|
DynamicMessageTypeBuilder::get_name() const
|
||||||
|
{
|
||||||
|
size_t buf_length;
|
||||||
|
const char * buf;
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_get_name(
|
||||||
|
&get_rosidl_dynamic_type_builder(), &buf, &buf_length);
|
||||||
|
return std::string(buf, buf_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t &
|
||||||
|
DynamicMessageTypeBuilder::get_rosidl_dynamic_type_builder()
|
||||||
|
{
|
||||||
|
return rosidl_dynamic_type_builder_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const rosidl_dynamic_typesupport_dynamic_type_builder_t &
|
||||||
|
DynamicMessageTypeBuilder::get_rosidl_dynamic_type_builder() const
|
||||||
|
{
|
||||||
|
return rosidl_dynamic_type_builder_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicSerializationSupport::SharedPtr
|
||||||
|
DynamicMessageTypeBuilder::get_shared_dynamic_serialization_support()
|
||||||
|
{
|
||||||
|
return serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicSerializationSupport::ConstSharedPtr
|
||||||
|
DynamicMessageTypeBuilder::get_shared_dynamic_serialization_support() const
|
||||||
|
{
|
||||||
|
return serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// METHODS =======================================================================================
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::set_name(const std::string & name)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_set_name(
|
||||||
|
&get_rosidl_dynamic_type_builder(), name.c_str(), name.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageTypeBuilder
|
||||||
|
DynamicMessageTypeBuilder::clone(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_clone(
|
||||||
|
&get_rosidl_dynamic_type_builder(), &allocator, &rosidl_dynamic_type_builder);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not clone dynamic type builder: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return DynamicMessageTypeBuilder(
|
||||||
|
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_type_builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageTypeBuilder::SharedPtr
|
||||||
|
DynamicMessageTypeBuilder::clone_shared(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder =
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_dynamic_type_builder();
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_clone(
|
||||||
|
&get_rosidl_dynamic_type_builder(), &allocator, &rosidl_dynamic_type_builder);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string("could not clone dynamic type builder: ") + rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
return DynamicMessageTypeBuilder::make_shared(
|
||||||
|
get_shared_dynamic_serialization_support(), std::move(rosidl_dynamic_type_builder));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::clear(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
if (!serialization_support_) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
"cannot call clear() on a dynamic type builder with uninitialized serialization support"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string & name = get_name();
|
||||||
|
init_from_serialization_support_(serialization_support_, name, allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage
|
||||||
|
DynamicMessageTypeBuilder::build_dynamic_message(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
return DynamicMessage(shared_from_this(), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
DynamicMessageTypeBuilder::build_dynamic_message_shared(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
return DynamicMessage::make_shared(shared_from_this(), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageType
|
||||||
|
DynamicMessageTypeBuilder::build_dynamic_message_type(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
return DynamicMessageType(shared_from_this(), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DynamicMessageType::SharedPtr
|
||||||
|
DynamicMessageTypeBuilder::build_dynamic_message_type_shared(rcl_allocator_t allocator)
|
||||||
|
{
|
||||||
|
return DynamicMessageType::make_shared(shared_from_this(), allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ADD MEMBERS =====================================================================================
|
||||||
|
// Defined in "detail/dynamic_message_type_builder_impl.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
// ADD FIXED STRING MEMBERS ========================================================================
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_fixed_string_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
string_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_fixed_wstring_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
wstring_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_fixed_string_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t string_length, size_t array_length, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_array_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
string_length, array_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_fixed_wstring_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t wstring_length, size_t array_length, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_array_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
wstring_length, array_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_fixed_string_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_unbounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
string_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_fixed_wstring_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_unbounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
wstring_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_fixed_string_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t string_length, size_t sequence_bound, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_bounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
string_length, sequence_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_fixed_wstring_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t wstring_length, size_t sequence_bound, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_bounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
wstring_length, sequence_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ADD BOUNDED STRING MEMBERS ======================================================================
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_string_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
string_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_wstring_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
wstring_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_string_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t string_bound, size_t array_length, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_array_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
string_bound, array_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_wstring_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t wstring_bound, size_t array_length, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_array_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
wstring_bound, array_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_string_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_unbounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
string_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_wstring_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_unbounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
wstring_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_string_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t string_bound, size_t sequence_bound, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_bounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
string_bound, sequence_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_bounded_wstring_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
size_t wstring_bound, size_t sequence_bound, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_bounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
wstring_bound, sequence_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ADD NESTED MEMBERS ==============================================================================
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_complex_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageType & nested_type, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
&nested_type.get_rosidl_dynamic_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_complex_array_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageType & nested_type, size_t array_length, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_array_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
&nested_type.get_rosidl_dynamic_type(), array_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_complex_unbounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageType & nested_type, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_unbounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
&nested_type.get_rosidl_dynamic_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_complex_bounded_sequence_member(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageType & nested_type, size_t sequence_bound, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_bounded_sequence_member(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
&nested_type.get_rosidl_dynamic_type(), sequence_bound);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_complex_member_builder(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_member_builder(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
&nested_type_builder.get_rosidl_dynamic_type_builder());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_complex_array_member_builder(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageTypeBuilder & nested_type_builder, size_t array_length,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_array_member_builder(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
&nested_type_builder.get_rosidl_dynamic_type_builder(), array_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_complex_unbounded_sequence_member_builder(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_unbounded_sequence_member_builder(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
&nested_type_builder.get_rosidl_dynamic_type_builder());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DynamicMessageTypeBuilder::add_complex_bounded_sequence_member_builder(
|
||||||
|
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||||
|
DynamicMessageTypeBuilder & nested_type_builder, size_t sequence_bound,
|
||||||
|
const std::string & default_value)
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_bounded_sequence_member_builder(
|
||||||
|
&get_rosidl_dynamic_type_builder(),
|
||||||
|
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
|
||||||
|
&nested_type_builder.get_rosidl_dynamic_type_builder(), sequence_bound);
|
||||||
|
}
|
||||||
@@ -0,0 +1,317 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <rosidl_dynamic_typesupport/identifier.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/types.h>
|
||||||
|
#include <rosidl_runtime_c/message_type_support_struct.h>
|
||||||
|
#include <rosidl_runtime_c/type_description_utils.h>
|
||||||
|
#include <rosidl_runtime_c/type_description/type_description__functions.h>
|
||||||
|
#include <rosidl_runtime_c/type_description/type_description__struct.h>
|
||||||
|
#include <rosidl_runtime_c/type_description/type_source__functions.h>
|
||||||
|
#include <rosidl_runtime_c/type_description/type_source__struct.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rcl/allocator.h"
|
||||||
|
#include "rcl/dynamic_message_type_support.h"
|
||||||
|
#include "rcl/type_hash.h"
|
||||||
|
#include "rcl/types.h"
|
||||||
|
#include "rcutils/logging_macros.h"
|
||||||
|
#include "rcutils/types/rcutils_ret.h"
|
||||||
|
#include "rmw/dynamic_message_type_support.h"
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message_type_support.hpp"
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/visibility_control.hpp"
|
||||||
|
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessage;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessageType;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessageTypeSupport;
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
|
||||||
|
|
||||||
|
// CONSTRUCTION ====================================================================================
|
||||||
|
DynamicMessageTypeSupport::DynamicMessageTypeSupport(
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
const std::string & serialization_library_name,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: serialization_support_(nullptr),
|
||||||
|
dynamic_message_type_(nullptr),
|
||||||
|
dynamic_message_(nullptr),
|
||||||
|
rosidl_message_type_support_(rosidl_get_zero_initialized_message_type_support_handle())
|
||||||
|
{
|
||||||
|
rcl_ret_t ret;
|
||||||
|
if (serialization_library_name.empty()) {
|
||||||
|
ret = rcl_dynamic_message_type_support_handle_init(
|
||||||
|
nullptr, &description, &allocator, &rosidl_message_type_support_);
|
||||||
|
} else {
|
||||||
|
ret = rcl_dynamic_message_type_support_handle_init(
|
||||||
|
serialization_library_name.c_str(), &description, &allocator, &rosidl_message_type_support_);
|
||||||
|
}
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
std::string error_msg =
|
||||||
|
std::string("error initializing rosidl message type support: ") + rcl_get_error_string().str;
|
||||||
|
rcl_reset_error();
|
||||||
|
throw std::runtime_error(error_msg);
|
||||||
|
}
|
||||||
|
if (rosidl_message_type_support_.typesupport_identifier !=
|
||||||
|
rosidl_get_dynamic_typesupport_identifier())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("rosidl message type support is of the wrong type");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ts_impl = static_cast<rosidl_dynamic_message_type_support_impl_t *>(const_cast<void *>(
|
||||||
|
rosidl_message_type_support_.data));
|
||||||
|
|
||||||
|
serialization_support_ = DynamicSerializationSupport::make_shared(
|
||||||
|
std::move(ts_impl->serialization_support));
|
||||||
|
|
||||||
|
dynamic_message_type_ = DynamicMessageType::make_shared(
|
||||||
|
get_shared_dynamic_serialization_support(), std::move(*ts_impl->dynamic_message_type));
|
||||||
|
|
||||||
|
dynamic_message_ = DynamicMessage::make_shared(
|
||||||
|
get_shared_dynamic_serialization_support(), std::move(*ts_impl->dynamic_message));
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicMessageTypeSupport::DynamicMessageTypeSupport(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: serialization_support_(serialization_support),
|
||||||
|
dynamic_message_type_(nullptr),
|
||||||
|
dynamic_message_(nullptr),
|
||||||
|
rosidl_message_type_support_(rosidl_get_zero_initialized_message_type_support_handle())
|
||||||
|
{
|
||||||
|
// Check null
|
||||||
|
if (!serialization_support) {
|
||||||
|
throw std::runtime_error("serialization_support cannot be nullptr.");
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_type_hash_t type_hash;
|
||||||
|
rcutils_ret_t hash_ret = rcl_calculate_type_hash(
|
||||||
|
// TODO(methylDragon): Swap this out with the conversion function when it is ready
|
||||||
|
reinterpret_cast<const type_description_interfaces__msg__TypeDescription *>(&description),
|
||||||
|
&type_hash);
|
||||||
|
if (hash_ret != RCL_RET_OK) {
|
||||||
|
throw std::runtime_error("failed to get type hash");
|
||||||
|
}
|
||||||
|
|
||||||
|
rcutils_ret_t ret = rosidl_dynamic_message_type_support_handle_init(
|
||||||
|
&serialization_support->get_rosidl_serialization_support(),
|
||||||
|
&type_hash, // type_hash
|
||||||
|
&description, // type_description
|
||||||
|
nullptr, // type_description_sources (not implemented for dynamic types)
|
||||||
|
&allocator,
|
||||||
|
&rosidl_message_type_support_);
|
||||||
|
if (ret != RCUTILS_RET_OK) {
|
||||||
|
throw std::runtime_error("could not init rosidl message type support");
|
||||||
|
}
|
||||||
|
if (rosidl_message_type_support_.typesupport_identifier !=
|
||||||
|
rosidl_get_dynamic_typesupport_identifier())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("rosidl message type support is of the wrong type");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ts_impl = static_cast<const rosidl_dynamic_message_type_support_impl_t *>(
|
||||||
|
rosidl_message_type_support_.data);
|
||||||
|
|
||||||
|
dynamic_message_type_ = DynamicMessageType::make_shared(
|
||||||
|
get_shared_dynamic_serialization_support(), std::move(*ts_impl->dynamic_message_type));
|
||||||
|
|
||||||
|
dynamic_message_ = DynamicMessage::make_shared(
|
||||||
|
get_shared_dynamic_serialization_support(), std::move(*ts_impl->dynamic_message));
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicMessageTypeSupport::DynamicMessageTypeSupport(
|
||||||
|
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||||
|
DynamicMessageType::SharedPtr dynamic_message_type,
|
||||||
|
DynamicMessage::SharedPtr dynamic_message,
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: serialization_support_(serialization_support),
|
||||||
|
dynamic_message_type_(dynamic_message_type),
|
||||||
|
dynamic_message_(dynamic_message),
|
||||||
|
rosidl_message_type_support_(rosidl_get_zero_initialized_message_type_support_handle())
|
||||||
|
{
|
||||||
|
// Check null
|
||||||
|
if (!serialization_support) {
|
||||||
|
throw std::runtime_error("serialization_support cannot be nullptr.");
|
||||||
|
}
|
||||||
|
if (!dynamic_message_type) {
|
||||||
|
throw std::runtime_error("dynamic_message_type cannot be nullptr.");
|
||||||
|
}
|
||||||
|
if (!dynamic_message) {
|
||||||
|
throw std::runtime_error("dynamic_message cannot be nullptr.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check identifiers
|
||||||
|
if (serialization_support->get_serialization_library_identifier() !=
|
||||||
|
dynamic_message_type->get_serialization_library_identifier())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"serialization support library identifier does not match "
|
||||||
|
"dynamic message type library identifier.");
|
||||||
|
}
|
||||||
|
if (dynamic_message_type->get_serialization_library_identifier() !=
|
||||||
|
dynamic_message->get_serialization_library_identifier())
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"dynamic message type library identifier does not match "
|
||||||
|
"dynamic message library identifier.");
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_type_hash_t type_hash;
|
||||||
|
rcutils_ret_t hash_ret = rcl_calculate_type_hash(
|
||||||
|
// TODO(methylDragon): Swap this out with the conversion function when it is ready
|
||||||
|
// from https://github.com/ros2/rcl/pull/1052
|
||||||
|
reinterpret_cast<const type_description_interfaces__msg__TypeDescription *>(&description),
|
||||||
|
&type_hash);
|
||||||
|
if (hash_ret != RCL_RET_OK) {
|
||||||
|
std::string error_msg = std::string("failed to get type hash: ") + rcl_get_error_string().str;
|
||||||
|
rcl_reset_error();
|
||||||
|
throw std::runtime_error(error_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ts_impl = static_cast<rosidl_dynamic_message_type_support_impl_t *>(
|
||||||
|
allocator.zero_allocate(1, sizeof(rosidl_dynamic_message_type_support_impl_t), allocator.state)
|
||||||
|
);
|
||||||
|
if (!ts_impl) {
|
||||||
|
throw std::runtime_error("could not allocate rosidl_message_type_support_t");
|
||||||
|
}
|
||||||
|
|
||||||
|
ts_impl->allocator = allocator;
|
||||||
|
ts_impl->type_hash = type_hash;
|
||||||
|
if (!rosidl_runtime_c__type_description__TypeDescription__copy(
|
||||||
|
&description, &ts_impl->type_description))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("could not copy type description");
|
||||||
|
}
|
||||||
|
// ts_impl->type_description_sources = // Not used
|
||||||
|
|
||||||
|
ts_impl->serialization_support = serialization_support->get_rosidl_serialization_support();
|
||||||
|
ts_impl->dynamic_message_type = &dynamic_message_type->get_rosidl_dynamic_type();
|
||||||
|
ts_impl->dynamic_message = &dynamic_message->get_rosidl_dynamic_data();
|
||||||
|
|
||||||
|
rosidl_message_type_support_ = {
|
||||||
|
rosidl_get_dynamic_typesupport_identifier(), // typesupport_identifier
|
||||||
|
ts_impl, // data
|
||||||
|
get_message_typesupport_handle_function, // func
|
||||||
|
// get_type_hash_func
|
||||||
|
rosidl_get_dynamic_message_type_support_type_hash_function,
|
||||||
|
// get_type_description_func
|
||||||
|
rosidl_get_dynamic_message_type_support_type_description_function,
|
||||||
|
// get_type_description_sources_func
|
||||||
|
rosidl_get_dynamic_message_type_support_type_description_sources_function
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicMessageTypeSupport::~DynamicMessageTypeSupport()
|
||||||
|
{
|
||||||
|
// These must go first
|
||||||
|
serialization_support_.reset();
|
||||||
|
dynamic_message_type_.reset();
|
||||||
|
dynamic_message_.reset();
|
||||||
|
|
||||||
|
// Early return if type support isn't populated to avoid segfaults
|
||||||
|
if (!rosidl_message_type_support_.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We only partially finalize the rosidl_message_type_support->data since its pointer members are
|
||||||
|
// managed by their respective SharedPtr wrapper classes.
|
||||||
|
auto ts_impl = static_cast<rosidl_dynamic_message_type_support_impl_t *>(
|
||||||
|
const_cast<void *>(rosidl_message_type_support_.data)
|
||||||
|
);
|
||||||
|
rcutils_allocator_t allocator = ts_impl->allocator;
|
||||||
|
|
||||||
|
rosidl_runtime_c__type_description__TypeDescription__fini(&ts_impl->type_description);
|
||||||
|
rosidl_runtime_c__type_description__TypeSource__Sequence__fini(
|
||||||
|
&ts_impl->type_description_sources);
|
||||||
|
allocator.deallocate(static_cast<void *>(ts_impl), allocator.state); // Always C allocated
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GETTERS =========================================================================================
|
||||||
|
const std::string
|
||||||
|
DynamicMessageTypeSupport::get_serialization_library_identifier() const
|
||||||
|
{
|
||||||
|
return serialization_support_->get_serialization_library_identifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_message_type_support_t &
|
||||||
|
DynamicMessageTypeSupport::get_rosidl_message_type_support()
|
||||||
|
{
|
||||||
|
return rosidl_message_type_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rosidl_message_type_support_t &
|
||||||
|
DynamicMessageTypeSupport::get_const_rosidl_message_type_support()
|
||||||
|
{
|
||||||
|
return rosidl_message_type_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rosidl_message_type_support_t &
|
||||||
|
DynamicMessageTypeSupport::get_const_rosidl_message_type_support() const
|
||||||
|
{
|
||||||
|
return rosidl_message_type_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rosidl_runtime_c__type_description__TypeDescription &
|
||||||
|
DynamicMessageTypeSupport::get_rosidl_runtime_c_type_description() const
|
||||||
|
{
|
||||||
|
auto ts_impl = static_cast<const rosidl_dynamic_message_type_support_impl_t *>(
|
||||||
|
get_const_rosidl_message_type_support().data
|
||||||
|
);
|
||||||
|
return ts_impl->type_description;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicSerializationSupport::SharedPtr
|
||||||
|
DynamicMessageTypeSupport::get_shared_dynamic_serialization_support()
|
||||||
|
{
|
||||||
|
return serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicSerializationSupport::ConstSharedPtr
|
||||||
|
DynamicMessageTypeSupport::get_shared_dynamic_serialization_support() const
|
||||||
|
{
|
||||||
|
return serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicMessageType::SharedPtr
|
||||||
|
DynamicMessageTypeSupport::get_shared_dynamic_message_type()
|
||||||
|
{
|
||||||
|
return dynamic_message_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicMessageType::ConstSharedPtr
|
||||||
|
DynamicMessageTypeSupport::get_shared_dynamic_message_type() const
|
||||||
|
{
|
||||||
|
return dynamic_message_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicMessage::SharedPtr
|
||||||
|
DynamicMessageTypeSupport::get_shared_dynamic_message()
|
||||||
|
{
|
||||||
|
return dynamic_message_;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicMessage::ConstSharedPtr
|
||||||
|
DynamicMessageTypeSupport::get_shared_dynamic_message() const
|
||||||
|
{
|
||||||
|
return dynamic_message_;
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <rcl/allocator.h>
|
||||||
|
#include <rcutils/logging_macros.h>
|
||||||
|
#include <rmw/dynamic_message_type_support.h>
|
||||||
|
#include <rmw/ret_types.h>
|
||||||
|
#include <rosidl_dynamic_typesupport/api/serialization_support.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
|
||||||
|
|
||||||
|
// CONSTRUCTION ====================================================================================
|
||||||
|
DynamicSerializationSupport::DynamicSerializationSupport(rcl_allocator_t allocator)
|
||||||
|
: DynamicSerializationSupport::DynamicSerializationSupport("", allocator) {}
|
||||||
|
|
||||||
|
DynamicSerializationSupport::DynamicSerializationSupport(
|
||||||
|
const std::string & serialization_library_name,
|
||||||
|
rcl_allocator_t allocator)
|
||||||
|
: rosidl_serialization_support_(
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_serialization_support())
|
||||||
|
{
|
||||||
|
rmw_ret_t ret = RMW_RET_ERROR;
|
||||||
|
|
||||||
|
if (serialization_library_name.empty()) {
|
||||||
|
ret = rmw_serialization_support_init(NULL, &allocator, &rosidl_serialization_support_);
|
||||||
|
} else {
|
||||||
|
ret = rmw_serialization_support_init(
|
||||||
|
serialization_library_name.c_str(), &allocator, &rosidl_serialization_support_);
|
||||||
|
}
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
std::string error_msg =
|
||||||
|
std::string("could not initialize new serialization support object: ") +
|
||||||
|
rcl_get_error_string().str;
|
||||||
|
rcl_reset_error();
|
||||||
|
throw std::runtime_error(error_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicSerializationSupport::DynamicSerializationSupport(
|
||||||
|
rosidl_dynamic_typesupport_serialization_support_t && rosidl_serialization_support)
|
||||||
|
: rosidl_serialization_support_(std::move(rosidl_serialization_support)) {}
|
||||||
|
|
||||||
|
DynamicSerializationSupport::DynamicSerializationSupport(
|
||||||
|
DynamicSerializationSupport && other) noexcept
|
||||||
|
: rosidl_serialization_support_(std::exchange(
|
||||||
|
other.rosidl_serialization_support_,
|
||||||
|
rosidl_dynamic_typesupport_get_zero_initialized_serialization_support())) {}
|
||||||
|
|
||||||
|
DynamicSerializationSupport &
|
||||||
|
DynamicSerializationSupport::operator=(DynamicSerializationSupport && other) noexcept
|
||||||
|
{
|
||||||
|
std::swap(rosidl_serialization_support_, other.rosidl_serialization_support_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicSerializationSupport::~DynamicSerializationSupport()
|
||||||
|
{
|
||||||
|
rosidl_dynamic_typesupport_serialization_support_fini(&rosidl_serialization_support_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GETTERS =========================================================================================
|
||||||
|
const std::string
|
||||||
|
DynamicSerializationSupport::get_serialization_library_identifier() const
|
||||||
|
{
|
||||||
|
return std::string(
|
||||||
|
rosidl_dynamic_typesupport_serialization_support_get_library_identifier(
|
||||||
|
&rosidl_serialization_support_));
|
||||||
|
}
|
||||||
|
|
||||||
|
rosidl_dynamic_typesupport_serialization_support_t &
|
||||||
|
DynamicSerializationSupport::get_rosidl_serialization_support()
|
||||||
|
{
|
||||||
|
return rosidl_serialization_support_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rosidl_dynamic_typesupport_serialization_support_t &
|
||||||
|
DynamicSerializationSupport::get_rosidl_serialization_support() const
|
||||||
|
{
|
||||||
|
return rosidl_serialization_support_;
|
||||||
|
}
|
||||||
@@ -12,9 +12,13 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "rclcpp/qos_event.hpp"
|
#include "rcl/event.h"
|
||||||
|
|
||||||
|
#include "rclcpp/event_handler.hpp"
|
||||||
|
#include "rclcpp/exceptions/exceptions.hpp"
|
||||||
|
|
||||||
namespace rclcpp
|
namespace rclcpp
|
||||||
{
|
{
|
||||||
@@ -33,11 +37,14 @@ UnsupportedEventTypeException::UnsupportedEventTypeException(
|
|||||||
std::runtime_error(prefix + (prefix.empty() ? "" : ": ") + base_exc.formatted_message)
|
std::runtime_error(prefix + (prefix.empty() ? "" : ": ") + base_exc.formatted_message)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
QOSEventHandlerBase::~QOSEventHandlerBase()
|
EventHandlerBase::~EventHandlerBase()
|
||||||
{
|
{
|
||||||
if (on_new_event_callback_) {
|
// Since the rmw event listener holds a reference to
|
||||||
clear_on_ready_callback();
|
// this callback, we need to clear it on destruction of this class.
|
||||||
}
|
// This clearing is not needed for other rclcpp entities like pub/subs, since
|
||||||
|
// they do own the underlying rmw entities, which are destroyed
|
||||||
|
// on their rclcpp destructors, thus no risk of dangling pointers.
|
||||||
|
clear_on_ready_callback();
|
||||||
|
|
||||||
if (rcl_event_fini(&event_handle_) != RCL_RET_OK) {
|
if (rcl_event_fini(&event_handle_) != RCL_RET_OK) {
|
||||||
RCUTILS_LOG_ERROR_NAMED(
|
RCUTILS_LOG_ERROR_NAMED(
|
||||||
@@ -49,14 +56,14 @@ QOSEventHandlerBase::~QOSEventHandlerBase()
|
|||||||
|
|
||||||
/// Get the number of ready events.
|
/// Get the number of ready events.
|
||||||
size_t
|
size_t
|
||||||
QOSEventHandlerBase::get_number_of_ready_events()
|
EventHandlerBase::get_number_of_ready_events()
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add the Waitable to a wait set.
|
/// Add the Waitable to a wait set.
|
||||||
void
|
void
|
||||||
QOSEventHandlerBase::add_to_wait_set(rcl_wait_set_t * wait_set)
|
EventHandlerBase::add_to_wait_set(rcl_wait_set_t * wait_set)
|
||||||
{
|
{
|
||||||
rcl_ret_t ret = rcl_wait_set_add_event(wait_set, &event_handle_, &wait_set_event_index_);
|
rcl_ret_t ret = rcl_wait_set_add_event(wait_set, &event_handle_, &wait_set_event_index_);
|
||||||
if (RCL_RET_OK != ret) {
|
if (RCL_RET_OK != ret) {
|
||||||
@@ -66,13 +73,13 @@ QOSEventHandlerBase::add_to_wait_set(rcl_wait_set_t * wait_set)
|
|||||||
|
|
||||||
/// Check if the Waitable is ready.
|
/// Check if the Waitable is ready.
|
||||||
bool
|
bool
|
||||||
QOSEventHandlerBase::is_ready(rcl_wait_set_t * wait_set)
|
EventHandlerBase::is_ready(rcl_wait_set_t * wait_set)
|
||||||
{
|
{
|
||||||
return wait_set->events[wait_set_event_index_] == &event_handle_;
|
return wait_set->events[wait_set_event_index_] == &event_handle_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QOSEventHandlerBase::set_on_new_event_callback(
|
EventHandlerBase::set_on_new_event_callback(
|
||||||
rcl_event_callback_t callback,
|
rcl_event_callback_t callback,
|
||||||
const void * user_data)
|
const void * user_data)
|
||||||
{
|
{
|
||||||
@@ -83,7 +90,7 @@ QOSEventHandlerBase::set_on_new_event_callback(
|
|||||||
|
|
||||||
if (RCL_RET_OK != ret) {
|
if (RCL_RET_OK != ret) {
|
||||||
using rclcpp::exceptions::throw_from_rcl_error;
|
using rclcpp::exceptions::throw_from_rcl_error;
|
||||||
throw_from_rcl_error(ret, "failed to set the on new message callback for QOS Event");
|
throw_from_rcl_error(ret, "failed to set the on new message callback for Event");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
#include "rcl/error_handling.h"
|
#include "rcl/error_handling.h"
|
||||||
#include "rcpputils/scope_exit.hpp"
|
#include "rcpputils/scope_exit.hpp"
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||||
#include "rclcpp/exceptions.hpp"
|
#include "rclcpp/exceptions.hpp"
|
||||||
#include "rclcpp/executor.hpp"
|
#include "rclcpp/executor.hpp"
|
||||||
#include "rclcpp/guard_condition.hpp"
|
#include "rclcpp/guard_condition.hpp"
|
||||||
@@ -106,6 +107,12 @@ Executor::~Executor()
|
|||||||
weak_groups_associated_with_executor_to_nodes_.clear();
|
weak_groups_associated_with_executor_to_nodes_.clear();
|
||||||
weak_groups_to_nodes_associated_with_executor_.clear();
|
weak_groups_to_nodes_associated_with_executor_.clear();
|
||||||
weak_groups_to_nodes_.clear();
|
weak_groups_to_nodes_.clear();
|
||||||
|
for (const auto & pair : weak_groups_to_guard_conditions_) {
|
||||||
|
auto guard_condition = pair.second;
|
||||||
|
memory_strategy_->remove_guard_condition(guard_condition);
|
||||||
|
}
|
||||||
|
weak_groups_to_guard_conditions_.clear();
|
||||||
|
|
||||||
for (const auto & pair : weak_nodes_to_guard_conditions_) {
|
for (const auto & pair : weak_nodes_to_guard_conditions_) {
|
||||||
auto guard_condition = pair.second;
|
auto guard_condition = pair.second;
|
||||||
memory_strategy_->remove_guard_condition(guard_condition);
|
memory_strategy_->remove_guard_condition(guard_condition);
|
||||||
@@ -204,8 +211,7 @@ Executor::add_callback_group_to_map(
|
|||||||
if (has_executor.exchange(true)) {
|
if (has_executor.exchange(true)) {
|
||||||
throw std::runtime_error("Callback group has already been added to an executor.");
|
throw std::runtime_error("Callback group has already been added to an executor.");
|
||||||
}
|
}
|
||||||
bool is_new_node = !has_node(node_ptr, weak_groups_to_nodes_associated_with_executor_) &&
|
|
||||||
!has_node(node_ptr, weak_groups_associated_with_executor_to_nodes_);
|
|
||||||
rclcpp::CallbackGroup::WeakPtr weak_group_ptr = group_ptr;
|
rclcpp::CallbackGroup::WeakPtr weak_group_ptr = group_ptr;
|
||||||
auto insert_info =
|
auto insert_info =
|
||||||
weak_groups_to_nodes.insert(std::make_pair(weak_group_ptr, node_ptr));
|
weak_groups_to_nodes.insert(std::make_pair(weak_group_ptr, node_ptr));
|
||||||
@@ -215,21 +221,24 @@ Executor::add_callback_group_to_map(
|
|||||||
}
|
}
|
||||||
// Also add to the map that contains all callback groups
|
// Also add to the map that contains all callback groups
|
||||||
weak_groups_to_nodes_.insert(std::make_pair(weak_group_ptr, node_ptr));
|
weak_groups_to_nodes_.insert(std::make_pair(weak_group_ptr, node_ptr));
|
||||||
if (is_new_node) {
|
|
||||||
const auto & gc = node_ptr->get_notify_guard_condition();
|
if (node_ptr->get_context()->is_valid()) {
|
||||||
weak_nodes_to_guard_conditions_[node_ptr] = &gc;
|
auto callback_group_guard_condition =
|
||||||
if (notify) {
|
group_ptr->get_notify_guard_condition(node_ptr->get_context());
|
||||||
// Interrupt waiting to handle new node
|
weak_groups_to_guard_conditions_[weak_group_ptr] = callback_group_guard_condition.get();
|
||||||
try {
|
// Add the callback_group's notify condition to the guard condition handles
|
||||||
interrupt_guard_condition_.trigger();
|
memory_strategy_->add_guard_condition(*callback_group_guard_condition);
|
||||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
}
|
||||||
throw std::runtime_error(
|
|
||||||
std::string(
|
if (notify) {
|
||||||
"Failed to trigger guard condition on callback group add: ") + ex.what());
|
// Interrupt waiting to handle new node
|
||||||
}
|
try {
|
||||||
|
interrupt_guard_condition_.trigger();
|
||||||
|
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||||
|
throw std::runtime_error(
|
||||||
|
std::string(
|
||||||
|
"Failed to trigger guard condition on callback group add: ") + ex.what());
|
||||||
}
|
}
|
||||||
// Add the node's notify condition to the guard condition handles
|
|
||||||
memory_strategy_->add_guard_condition(gc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,6 +281,10 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const auto & gc = node_ptr->get_notify_guard_condition();
|
||||||
|
weak_nodes_to_guard_conditions_[node_ptr] = &gc;
|
||||||
|
// Add the node's notify condition to the guard condition handles
|
||||||
|
memory_strategy_->add_guard_condition(gc);
|
||||||
weak_nodes_.push_back(node_ptr);
|
weak_nodes_.push_back(node_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,7 +313,12 @@ Executor::remove_callback_group_from_map(
|
|||||||
if (!has_node(node_ptr, weak_groups_to_nodes_associated_with_executor_) &&
|
if (!has_node(node_ptr, weak_groups_to_nodes_associated_with_executor_) &&
|
||||||
!has_node(node_ptr, weak_groups_associated_with_executor_to_nodes_))
|
!has_node(node_ptr, weak_groups_associated_with_executor_to_nodes_))
|
||||||
{
|
{
|
||||||
weak_nodes_to_guard_conditions_.erase(node_ptr);
|
auto iter = weak_groups_to_guard_conditions_.find(weak_group_ptr);
|
||||||
|
if (iter != weak_groups_to_guard_conditions_.end()) {
|
||||||
|
memory_strategy_->remove_guard_condition(iter->second);
|
||||||
|
}
|
||||||
|
weak_groups_to_guard_conditions_.erase(weak_group_ptr);
|
||||||
|
|
||||||
if (notify) {
|
if (notify) {
|
||||||
try {
|
try {
|
||||||
interrupt_guard_condition_.trigger();
|
interrupt_guard_condition_.trigger();
|
||||||
@@ -310,7 +328,6 @@ Executor::remove_callback_group_from_map(
|
|||||||
"Failed to trigger guard condition on callback group remove: ") + ex.what());
|
"Failed to trigger guard condition on callback group remove: ") + ex.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
memory_strategy_->remove_guard_condition(&node_ptr->get_notify_guard_condition());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,6 +389,9 @@ Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memory_strategy_->remove_guard_condition(&node_ptr->get_notify_guard_condition());
|
||||||
|
weak_nodes_to_guard_conditions_.erase(node_ptr);
|
||||||
|
|
||||||
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
|
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
|
||||||
has_executor.store(false);
|
has_executor.store(false);
|
||||||
}
|
}
|
||||||
@@ -539,13 +559,14 @@ Executor::execute_any_executable(AnyExecutable & any_exec)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Taker, typename Handler>
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
take_and_do_error_handling(
|
take_and_do_error_handling(
|
||||||
const char * action_description,
|
const char * action_description,
|
||||||
const char * topic_or_service_name,
|
const char * topic_or_service_name,
|
||||||
std::function<bool()> take_action,
|
Taker take_action,
|
||||||
std::function<void()> handle_action)
|
Handler handle_action)
|
||||||
{
|
{
|
||||||
bool taken = false;
|
bool taken = false;
|
||||||
try {
|
try {
|
||||||
@@ -578,70 +599,136 @@ take_and_do_error_handling(
|
|||||||
void
|
void
|
||||||
Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
|
Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
|
||||||
{
|
{
|
||||||
|
using rclcpp::dynamic_typesupport::DynamicMessage;
|
||||||
|
|
||||||
rclcpp::MessageInfo message_info;
|
rclcpp::MessageInfo message_info;
|
||||||
message_info.get_rmw_message_info().from_intra_process = false;
|
message_info.get_rmw_message_info().from_intra_process = false;
|
||||||
|
|
||||||
if (subscription->is_serialized()) {
|
switch (subscription->get_subscription_type()) {
|
||||||
// This is the case where a copy of the serialized message is taken from
|
// Take ROS message
|
||||||
// the middleware via inter-process communication.
|
case rclcpp::SubscriptionType::ROS_MESSAGE:
|
||||||
std::shared_ptr<SerializedMessage> serialized_msg = subscription->create_serialized_message();
|
|
||||||
take_and_do_error_handling(
|
|
||||||
"taking a serialized message from topic",
|
|
||||||
subscription->get_topic_name(),
|
|
||||||
[&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
|
|
||||||
[&]()
|
|
||||||
{
|
{
|
||||||
subscription->handle_serialized_message(serialized_msg, message_info);
|
if (subscription->can_loan_messages()) {
|
||||||
});
|
// This is the case where a loaned message is taken from the middleware via
|
||||||
subscription->return_serialized_message(serialized_msg);
|
// inter-process communication, given to the user for their callback,
|
||||||
} else if (subscription->can_loan_messages()) {
|
// and then returned.
|
||||||
// This is the case where a loaned message is taken from the middleware via
|
void * loaned_msg = nullptr;
|
||||||
// inter-process communication, given to the user for their callback,
|
// TODO(wjwwood): refactor this into methods on subscription when LoanedMessage
|
||||||
// and then returned.
|
// is extened to support subscriptions as well.
|
||||||
void * loaned_msg = nullptr;
|
take_and_do_error_handling(
|
||||||
// TODO(wjwwood): refactor this into methods on subscription when LoanedMessage
|
"taking a loaned message from topic",
|
||||||
// is extened to support subscriptions as well.
|
subscription->get_topic_name(),
|
||||||
take_and_do_error_handling(
|
[&]()
|
||||||
"taking a loaned message from topic",
|
{
|
||||||
subscription->get_topic_name(),
|
rcl_ret_t ret = rcl_take_loaned_message(
|
||||||
[&]()
|
subscription->get_subscription_handle().get(),
|
||||||
{
|
&loaned_msg,
|
||||||
rcl_ret_t ret = rcl_take_loaned_message(
|
&message_info.get_rmw_message_info(),
|
||||||
subscription->get_subscription_handle().get(),
|
nullptr);
|
||||||
&loaned_msg,
|
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
|
||||||
&message_info.get_rmw_message_info(),
|
return false;
|
||||||
nullptr);
|
} else if (RCL_RET_OK != ret) {
|
||||||
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
|
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||||
return false;
|
}
|
||||||
} else if (RCL_RET_OK != ret) {
|
return true;
|
||||||
rclcpp::exceptions::throw_from_rcl_error(ret);
|
},
|
||||||
|
[&]() {subscription->handle_loaned_message(loaned_msg, message_info);});
|
||||||
|
if (nullptr != loaned_msg) {
|
||||||
|
rcl_ret_t ret = rcl_return_loaned_message_from_subscription(
|
||||||
|
subscription->get_subscription_handle().get(), loaned_msg);
|
||||||
|
if (RCL_RET_OK != ret) {
|
||||||
|
RCLCPP_ERROR(
|
||||||
|
rclcpp::get_logger("rclcpp"),
|
||||||
|
"rcl_return_loaned_message_from_subscription() failed for subscription on topic "
|
||||||
|
"'%s': %s",
|
||||||
|
subscription->get_topic_name(), rcl_get_error_string().str);
|
||||||
|
}
|
||||||
|
loaned_msg = nullptr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This case is taking a copy of the message data from the middleware via
|
||||||
|
// inter-process communication.
|
||||||
|
std::shared_ptr<void> message = subscription->create_message();
|
||||||
|
take_and_do_error_handling(
|
||||||
|
"taking a message from topic",
|
||||||
|
subscription->get_topic_name(),
|
||||||
|
[&]() {return subscription->take_type_erased(message.get(), message_info);},
|
||||||
|
[&]() {subscription->handle_message(message, message_info);});
|
||||||
|
subscription->return_message(message);
|
||||||
}
|
}
|
||||||
return true;
|
break;
|
||||||
},
|
}
|
||||||
[&]() {subscription->handle_loaned_message(loaned_msg, message_info);});
|
|
||||||
if (nullptr != loaned_msg) {
|
// Take serialized message
|
||||||
rcl_ret_t ret = rcl_return_loaned_message_from_subscription(
|
case rclcpp::SubscriptionType::SERIALIZED_MESSAGE:
|
||||||
subscription->get_subscription_handle().get(),
|
{
|
||||||
loaned_msg);
|
// This is the case where a copy of the serialized message is taken from
|
||||||
if (RCL_RET_OK != ret) {
|
// the middleware via inter-process communication.
|
||||||
RCLCPP_ERROR(
|
std::shared_ptr<SerializedMessage> serialized_msg =
|
||||||
rclcpp::get_logger("rclcpp"),
|
subscription->create_serialized_message();
|
||||||
"rcl_return_loaned_message_from_subscription() failed for subscription on topic '%s': %s",
|
take_and_do_error_handling(
|
||||||
subscription->get_topic_name(), rcl_get_error_string().str);
|
"taking a serialized message from topic",
|
||||||
|
subscription->get_topic_name(),
|
||||||
|
[&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
|
||||||
|
[&]()
|
||||||
|
{
|
||||||
|
subscription->handle_serialized_message(serialized_msg, message_info);
|
||||||
|
});
|
||||||
|
subscription->return_serialized_message(serialized_msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DYNAMIC SUBSCRIPTION ========================================================================
|
||||||
|
// If a subscription is dynamic, then it will use its serialization-specific dynamic data.
|
||||||
|
//
|
||||||
|
// Two cases:
|
||||||
|
// - Dynamic type subscription using dynamic type stored in its own internal type support struct
|
||||||
|
// - Non-dynamic type subscription with no stored dynamic type
|
||||||
|
// - Subscriptions of this type must be able to lookup the local message description to
|
||||||
|
// generate a dynamic type at runtime!
|
||||||
|
// - TODO(methylDragon): I won't be handling this case yet
|
||||||
|
|
||||||
|
// Take dynamic message directly from the middleware
|
||||||
|
case rclcpp::SubscriptionType::DYNAMIC_MESSAGE_DIRECT:
|
||||||
|
{
|
||||||
|
DynamicMessage::SharedPtr dynamic_message = subscription->create_dynamic_message();
|
||||||
|
take_and_do_error_handling(
|
||||||
|
"taking a dynamic message from topic",
|
||||||
|
subscription->get_topic_name(),
|
||||||
|
// This modifies the stored dynamic data in the DynamicMessage in-place
|
||||||
|
[&]() {return subscription->take_dynamic_message(*dynamic_message, message_info);},
|
||||||
|
[&]() {subscription->handle_dynamic_message(dynamic_message, message_info);});
|
||||||
|
subscription->return_dynamic_message(dynamic_message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take serialized and then convert to dynamic message
|
||||||
|
case rclcpp::SubscriptionType::DYNAMIC_MESSAGE_FROM_SERIALIZED:
|
||||||
|
{
|
||||||
|
std::shared_ptr<SerializedMessage> serialized_msg =
|
||||||
|
subscription->create_serialized_message();
|
||||||
|
|
||||||
|
// NOTE(methylDragon): Is this clone necessary? If I'm following the pattern, it seems so.
|
||||||
|
DynamicMessage::SharedPtr dynamic_message = subscription->create_dynamic_message();
|
||||||
|
take_and_do_error_handling(
|
||||||
|
"taking a serialized message from topic",
|
||||||
|
subscription->get_topic_name(),
|
||||||
|
[&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
|
||||||
|
[&]()
|
||||||
|
{
|
||||||
|
bool ret = dynamic_message->deserialize(serialized_msg->get_rcl_serialized_message());
|
||||||
|
if (!ret) {
|
||||||
|
throw_from_rcl_error(ret, "Couldn't convert serialized message to dynamic data!");
|
||||||
|
}
|
||||||
|
subscription->handle_dynamic_message(dynamic_message, message_info);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
subscription->return_serialized_message(serialized_msg);
|
||||||
|
subscription->return_dynamic_message(dynamic_message);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
loaned_msg = nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This case is taking a copy of the message data from the middleware via
|
|
||||||
// inter-process communication.
|
|
||||||
std::shared_ptr<void> message = subscription->create_message();
|
|
||||||
take_and_do_error_handling(
|
|
||||||
"taking a message from topic",
|
|
||||||
subscription->get_topic_name(),
|
|
||||||
[&]() {return subscription->take_type_erased(message.get(), message_info);},
|
|
||||||
[&]() {subscription->handle_message(message, message_info);});
|
|
||||||
subscription->return_message(message);
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -721,6 +808,12 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
|
|||||||
{
|
{
|
||||||
weak_groups_associated_with_executor_to_nodes_.erase(group_ptr);
|
weak_groups_associated_with_executor_to_nodes_.erase(group_ptr);
|
||||||
}
|
}
|
||||||
|
auto callback_guard_pair = weak_groups_to_guard_conditions_.find(group_ptr);
|
||||||
|
if (callback_guard_pair != weak_groups_to_guard_conditions_.end()) {
|
||||||
|
auto guard_condition = callback_guard_pair->second;
|
||||||
|
weak_groups_to_guard_conditions_.erase(group_ptr);
|
||||||
|
memory_strategy_->remove_guard_condition(guard_condition);
|
||||||
|
}
|
||||||
weak_groups_to_nodes_.erase(group_ptr);
|
weak_groups_to_nodes_.erase(group_ptr);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include "rcpputils/scope_exit.hpp"
|
#include "rcpputils/scope_exit.hpp"
|
||||||
|
|
||||||
|
#include "rclcpp/logging.hpp"
|
||||||
#include "rclcpp/utilities.hpp"
|
#include "rclcpp/utilities.hpp"
|
||||||
|
|
||||||
using rclcpp::executors::MultiThreadedExecutor;
|
using rclcpp::executors::MultiThreadedExecutor;
|
||||||
@@ -34,9 +35,15 @@ MultiThreadedExecutor::MultiThreadedExecutor(
|
|||||||
yield_before_execute_(yield_before_execute),
|
yield_before_execute_(yield_before_execute),
|
||||||
next_exec_timeout_(next_exec_timeout)
|
next_exec_timeout_(next_exec_timeout)
|
||||||
{
|
{
|
||||||
number_of_threads_ = number_of_threads ? number_of_threads : std::thread::hardware_concurrency();
|
number_of_threads_ = number_of_threads > 0 ?
|
||||||
if (number_of_threads_ == 0) {
|
number_of_threads :
|
||||||
number_of_threads_ = 1;
|
std::max(std::thread::hardware_concurrency(), 2U);
|
||||||
|
|
||||||
|
if (number_of_threads_ == 1) {
|
||||||
|
RCLCPP_WARN(
|
||||||
|
rclcpp::get_logger("rclcpp"),
|
||||||
|
"MultiThreadedExecutor is used with a single thread.\n"
|
||||||
|
"Use the SingleThreadedExecutor instead.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ void GenericSubscription::handle_message(
|
|||||||
"handle_message is not implemented for GenericSubscription");
|
"handle_message is not implemented for GenericSubscription");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void GenericSubscription::handle_serialized_message(
|
||||||
GenericSubscription::handle_serialized_message(
|
|
||||||
const std::shared_ptr<rclcpp::SerializedMessage> & message,
|
const std::shared_ptr<rclcpp::SerializedMessage> & message,
|
||||||
const rclcpp::MessageInfo &)
|
const rclcpp::MessageInfo &)
|
||||||
{
|
{
|
||||||
@@ -72,4 +71,55 @@ void GenericSubscription::return_serialized_message(
|
|||||||
message.reset();
|
message.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DYNAMIC TYPE ====================================================================================
|
||||||
|
// TODO(methylDragon): Reorder later
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
|
||||||
|
GenericSubscription::get_shared_dynamic_message_type()
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"get_shared_dynamic_message_type is not implemented for GenericSubscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
|
||||||
|
GenericSubscription::get_shared_dynamic_message()
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"get_shared_dynamic_message is not implemented for GenericSubscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
|
||||||
|
GenericSubscription::get_shared_dynamic_serialization_support()
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"get_shared_dynamic_serialization_support is not implemented for GenericSubscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
|
||||||
|
GenericSubscription::create_dynamic_message()
|
||||||
|
{
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"create_dynamic_message is not implemented for GenericSubscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GenericSubscription::return_dynamic_message(
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
|
||||||
|
{
|
||||||
|
(void) message;
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"return_dynamic_message is not implemented for GenericSubscription");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
GenericSubscription::handle_dynamic_message(
|
||||||
|
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
|
||||||
|
const rclcpp::MessageInfo & message_info)
|
||||||
|
{
|
||||||
|
(void) message;
|
||||||
|
(void) message_info;
|
||||||
|
throw rclcpp::exceptions::UnimplementedError(
|
||||||
|
"handle_dynamic_message is not implemented for GenericSubscription");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|||||||
@@ -12,14 +12,19 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "rcl_logging_interface/rcl_logging_interface.h"
|
#include "rcl_logging_interface/rcl_logging_interface.h"
|
||||||
|
#include "rcl/logging_rosout.h"
|
||||||
|
|
||||||
#include "rclcpp/exceptions.hpp"
|
#include "rclcpp/exceptions.hpp"
|
||||||
#include "rclcpp/logger.hpp"
|
#include "rclcpp/logger.hpp"
|
||||||
#include "rclcpp/logging.hpp"
|
#include "rclcpp/logging.hpp"
|
||||||
|
|
||||||
|
#include "./logging_mutex.hpp"
|
||||||
|
|
||||||
namespace rclcpp
|
namespace rclcpp
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -62,6 +67,46 @@ get_logging_directory()
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger
|
||||||
|
Logger::get_child(const std::string & suffix)
|
||||||
|
{
|
||||||
|
if (!name_) {
|
||||||
|
return Logger();
|
||||||
|
}
|
||||||
|
|
||||||
|
rcl_ret_t rcl_ret = RCL_RET_OK;
|
||||||
|
std::shared_ptr<std::recursive_mutex> logging_mutex;
|
||||||
|
logging_mutex = get_global_logging_mutex();
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
|
||||||
|
rcl_ret = rcl_logging_rosout_add_sublogger((*name_).c_str(), suffix.c_str());
|
||||||
|
if (RCL_RET_OK != rcl_ret) {
|
||||||
|
exceptions::throw_from_rcl_error(
|
||||||
|
rcl_ret, "failed to call rcl_logging_rosout_add_sublogger",
|
||||||
|
rcutils_get_error_state(), rcutils_reset_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger logger(*name_ + RCUTILS_LOGGING_SEPARATOR_STRING + suffix);
|
||||||
|
if (RCL_RET_OK == rcl_ret) {
|
||||||
|
logger.logger_sublogger_pairname_.reset(
|
||||||
|
new std::pair<std::string, std::string>({*name_, suffix}),
|
||||||
|
[logging_mutex](std::pair<std::string, std::string> * logger_sublogger_pairname_ptr) {
|
||||||
|
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
|
||||||
|
rcl_ret_t rcl_ret = rcl_logging_rosout_remove_sublogger(
|
||||||
|
logger_sublogger_pairname_ptr->first.c_str(),
|
||||||
|
logger_sublogger_pairname_ptr->second.c_str());
|
||||||
|
delete logger_sublogger_pairname_ptr;
|
||||||
|
if (RCL_RET_OK != rcl_ret) {
|
||||||
|
exceptions::throw_from_rcl_error(
|
||||||
|
rcl_ret, "failed to call rcl_logging_rosout_remove_sublogger",
|
||||||
|
rcutils_get_error_state(), rcutils_reset_error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Logger::set_level(Level level)
|
Logger::set_level(Level level)
|
||||||
{
|
{
|
||||||
@@ -80,4 +125,18 @@ Logger::set_level(Level level)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger::Level
|
||||||
|
Logger::get_effective_level() const
|
||||||
|
{
|
||||||
|
int logger_level = rcutils_logging_get_logger_effective_level(get_name());
|
||||||
|
|
||||||
|
if (logger_level < 0) {
|
||||||
|
exceptions::throw_from_rcl_error(
|
||||||
|
RCL_RET_ERROR, "Couldn't get logger level",
|
||||||
|
rcutils_get_error_state(), rcutils_reset_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<Level>(logger_level);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace rclcpp
|
} // namespace rclcpp
|
||||||
|
|||||||
@@ -176,7 +176,8 @@ Node::Node(
|
|||||||
node_topics_,
|
node_topics_,
|
||||||
node_graph_,
|
node_graph_,
|
||||||
node_services_,
|
node_services_,
|
||||||
node_logging_
|
node_logging_,
|
||||||
|
options.clock_type()
|
||||||
)),
|
)),
|
||||||
node_parameters_(new rclcpp::node_interfaces::NodeParameters(
|
node_parameters_(new rclcpp::node_interfaces::NodeParameters(
|
||||||
node_base_,
|
node_base_,
|
||||||
|
|||||||
@@ -24,13 +24,14 @@ NodeClock::NodeClock(
|
|||||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
||||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
|
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
|
||||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging)
|
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||||
|
rcl_clock_type_t clock_type)
|
||||||
: node_base_(node_base),
|
: node_base_(node_base),
|
||||||
node_topics_(node_topics),
|
node_topics_(node_topics),
|
||||||
node_graph_(node_graph),
|
node_graph_(node_graph),
|
||||||
node_services_(node_services),
|
node_services_(node_services),
|
||||||
node_logging_(node_logging),
|
node_logging_(node_logging),
|
||||||
ros_clock_(std::make_shared<rclcpp::Clock>(RCL_ROS_TIME))
|
clock_(std::make_shared<rclcpp::Clock>(clock_type))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
NodeClock::~NodeClock()
|
NodeClock::~NodeClock()
|
||||||
@@ -39,11 +40,11 @@ NodeClock::~NodeClock()
|
|||||||
rclcpp::Clock::SharedPtr
|
rclcpp::Clock::SharedPtr
|
||||||
NodeClock::get_clock()
|
NodeClock::get_clock()
|
||||||
{
|
{
|
||||||
return ros_clock_;
|
return clock_;
|
||||||
}
|
}
|
||||||
|
|
||||||
rclcpp::Clock::ConstSharedPtr
|
rclcpp::Clock::ConstSharedPtr
|
||||||
NodeClock::get_clock() const
|
NodeClock::get_clock() const
|
||||||
{
|
{
|
||||||
return ros_clock_;
|
return clock_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -651,7 +651,7 @@ NodeParameters::undeclare_parameter(const std::string & name)
|
|||||||
}
|
}
|
||||||
if (!parameter_info->second.descriptor.dynamic_typing) {
|
if (!parameter_info->second.descriptor.dynamic_typing) {
|
||||||
throw rclcpp::exceptions::InvalidParameterTypeException{
|
throw rclcpp::exceptions::InvalidParameterTypeException{
|
||||||
name, "cannot undeclare an statically typed parameter"};
|
name, "cannot undeclare a statically typed parameter"};
|
||||||
}
|
}
|
||||||
|
|
||||||
parameters_.erase(parameter_info);
|
parameters_.erase(parameter_info);
|
||||||
@@ -824,7 +824,7 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
|||||||
auto it = parameters_.find(parameter.get_name());
|
auto it = parameters_.find(parameter.get_name());
|
||||||
if (it != parameters_.end() && rclcpp::PARAMETER_NOT_SET != it->second.value.get_type()) {
|
if (it != parameters_.end() && rclcpp::PARAMETER_NOT_SET != it->second.value.get_type()) {
|
||||||
if (!it->second.descriptor.dynamic_typing) {
|
if (!it->second.descriptor.dynamic_typing) {
|
||||||
result.reason = "cannot undeclare an statically typed parameter";
|
result.reason = "cannot undeclare a statically typed parameter";
|
||||||
result.successful = false;
|
result.successful = false;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -904,22 +904,12 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
|||||||
std::vector<rclcpp::Parameter>
|
std::vector<rclcpp::Parameter>
|
||||||
NodeParameters::get_parameters(const std::vector<std::string> & names) const
|
NodeParameters::get_parameters(const std::vector<std::string> & names) const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
|
||||||
std::vector<rclcpp::Parameter> results;
|
std::vector<rclcpp::Parameter> results;
|
||||||
results.reserve(names.size());
|
results.reserve(names.size());
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||||
for (auto & name : names) {
|
for (auto & name : names) {
|
||||||
auto found_parameter = parameters_.find(name);
|
results.emplace_back(this->get_parameter(name));
|
||||||
if (found_parameter != parameters_.cend()) {
|
|
||||||
// found
|
|
||||||
results.emplace_back(name, found_parameter->second.value);
|
|
||||||
} else if (this->allow_undeclared_) {
|
|
||||||
// not found, but undeclared allowed
|
|
||||||
results.emplace_back(name, rclcpp::ParameterValue());
|
|
||||||
} else {
|
|
||||||
// not found, and undeclared are not allowed
|
|
||||||
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
@@ -930,18 +920,18 @@ NodeParameters::get_parameter(const std::string & name) const
|
|||||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||||
|
|
||||||
auto param_iter = parameters_.find(name);
|
auto param_iter = parameters_.find(name);
|
||||||
if (
|
if (parameters_.end() != param_iter) {
|
||||||
parameters_.end() != param_iter &&
|
if (
|
||||||
(param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET ||
|
param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET ||
|
||||||
param_iter->second.descriptor.dynamic_typing))
|
param_iter->second.descriptor.dynamic_typing)
|
||||||
{
|
{
|
||||||
return rclcpp::Parameter{name, param_iter->second.value};
|
return rclcpp::Parameter{name, param_iter->second.value};
|
||||||
} else if (this->allow_undeclared_) {
|
}
|
||||||
return rclcpp::Parameter{};
|
|
||||||
} else if (parameters_.end() == param_iter) {
|
|
||||||
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
|
||||||
} else {
|
|
||||||
throw rclcpp::exceptions::ParameterUninitializedException(name);
|
throw rclcpp::exceptions::ParameterUninitializedException(name);
|
||||||
|
} else if (this->allow_undeclared_) {
|
||||||
|
return rclcpp::Parameter{name};
|
||||||
|
} else {
|
||||||
|
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,15 +35,17 @@ NodeServices::add_service(
|
|||||||
// TODO(jacquelinekay): use custom exception
|
// TODO(jacquelinekay): use custom exception
|
||||||
throw std::runtime_error("Cannot create service, group not in node.");
|
throw std::runtime_error("Cannot create service, group not in node.");
|
||||||
}
|
}
|
||||||
group->add_service(service_base_ptr);
|
|
||||||
} else {
|
} else {
|
||||||
node_base_->get_default_callback_group()->add_service(service_base_ptr);
|
group = node_base_->get_default_callback_group();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group->add_service(service_base_ptr);
|
||||||
|
|
||||||
// Notify the executor that a new service was created using the parent Node.
|
// Notify the executor that a new service was created using the parent Node.
|
||||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||||
try {
|
try {
|
||||||
node_gc.trigger();
|
node_gc.trigger();
|
||||||
|
group->trigger_notify_guard_condition();
|
||||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
std::string("failed to notify wait set on service creation: ") + ex.what());
|
std::string("failed to notify wait set on service creation: ") + ex.what());
|
||||||
@@ -60,15 +62,17 @@ NodeServices::add_client(
|
|||||||
// TODO(jacquelinekay): use custom exception
|
// TODO(jacquelinekay): use custom exception
|
||||||
throw std::runtime_error("Cannot create client, group not in node.");
|
throw std::runtime_error("Cannot create client, group not in node.");
|
||||||
}
|
}
|
||||||
group->add_client(client_base_ptr);
|
|
||||||
} else {
|
} else {
|
||||||
node_base_->get_default_callback_group()->add_client(client_base_ptr);
|
group = node_base_->get_default_callback_group();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group->add_client(client_base_ptr);
|
||||||
|
|
||||||
// Notify the executor that a new client was created using the parent Node.
|
// Notify the executor that a new client was created using the parent Node.
|
||||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||||
try {
|
try {
|
||||||
node_gc.trigger();
|
node_gc.trigger();
|
||||||
|
group->trigger_notify_guard_condition();
|
||||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
std::string("failed to notify wait set on client creation: ") + ex.what());
|
std::string("failed to notify wait set on client creation: ") + ex.what());
|
||||||
|
|||||||
@@ -37,14 +37,15 @@ NodeTimers::add_timer(
|
|||||||
// TODO(jacquelinekay): use custom exception
|
// TODO(jacquelinekay): use custom exception
|
||||||
throw std::runtime_error("Cannot create timer, group not in node.");
|
throw std::runtime_error("Cannot create timer, group not in node.");
|
||||||
}
|
}
|
||||||
callback_group->add_timer(timer);
|
|
||||||
} else {
|
} else {
|
||||||
node_base_->get_default_callback_group()->add_timer(timer);
|
callback_group = node_base_->get_default_callback_group();
|
||||||
}
|
}
|
||||||
|
callback_group->add_timer(timer);
|
||||||
|
|
||||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||||
try {
|
try {
|
||||||
node_gc.trigger();
|
node_gc.trigger();
|
||||||
|
callback_group->trigger_notify_guard_condition();
|
||||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
std::string("failed to notify wait set on timer creation: ") + ex.what());
|
std::string("failed to notify wait set on timer creation: ") + ex.what());
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ NodeTopics::add_publisher(
|
|||||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||||
try {
|
try {
|
||||||
node_gc.trigger();
|
node_gc.trigger();
|
||||||
|
callback_group->trigger_notify_guard_condition();
|
||||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
std::string("failed to notify wait set on publisher creation: ") + ex.what());
|
std::string("failed to notify wait set on publisher creation: ") + ex.what());
|
||||||
@@ -121,6 +122,7 @@ NodeTopics::add_subscription(
|
|||||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||||
try {
|
try {
|
||||||
node_gc.trigger();
|
node_gc.trigger();
|
||||||
|
callback_group->trigger_notify_guard_condition();
|
||||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
std::string("failed to notify wait set on subscription creation: ") + ex.what());
|
std::string("failed to notify wait set on subscription creation: ") + ex.what());
|
||||||
|
|||||||
@@ -35,15 +35,17 @@ NodeWaitables::add_waitable(
|
|||||||
// TODO(jacobperron): use custom exception
|
// TODO(jacobperron): use custom exception
|
||||||
throw std::runtime_error("Cannot create waitable, group not in node.");
|
throw std::runtime_error("Cannot create waitable, group not in node.");
|
||||||
}
|
}
|
||||||
group->add_waitable(waitable_ptr);
|
|
||||||
} else {
|
} else {
|
||||||
node_base_->get_default_callback_group()->add_waitable(waitable_ptr);
|
group = node_base_->get_default_callback_group();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
group->add_waitable(waitable_ptr);
|
||||||
|
|
||||||
// Notify the executor that a new waitable was created using the parent Node.
|
// Notify the executor that a new waitable was created using the parent Node.
|
||||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||||
try {
|
try {
|
||||||
node_gc.trigger();
|
node_gc.trigger();
|
||||||
|
group->trigger_notify_guard_condition();
|
||||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
std::string("failed to notify wait set on waitable creation: ") + ex.what());
|
std::string("failed to notify wait set on waitable creation: ") + ex.what());
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ NodeOptions::operator=(const NodeOptions & other)
|
|||||||
this->enable_topic_statistics_ = other.enable_topic_statistics_;
|
this->enable_topic_statistics_ = other.enable_topic_statistics_;
|
||||||
this->start_parameter_services_ = other.start_parameter_services_;
|
this->start_parameter_services_ = other.start_parameter_services_;
|
||||||
this->start_parameter_event_publisher_ = other.start_parameter_event_publisher_;
|
this->start_parameter_event_publisher_ = other.start_parameter_event_publisher_;
|
||||||
|
this->clock_type_ = other.clock_type_;
|
||||||
this->clock_qos_ = other.clock_qos_;
|
this->clock_qos_ = other.clock_qos_;
|
||||||
this->use_clock_thread_ = other.use_clock_thread_;
|
this->use_clock_thread_ = other.use_clock_thread_;
|
||||||
this->parameter_event_qos_ = other.parameter_event_qos_;
|
this->parameter_event_qos_ = other.parameter_event_qos_;
|
||||||
@@ -260,6 +261,19 @@ NodeOptions::start_parameter_event_publisher(bool start_parameter_event_publishe
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const rcl_clock_type_t &
|
||||||
|
NodeOptions::clock_type() const
|
||||||
|
{
|
||||||
|
return this->clock_type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeOptions &
|
||||||
|
NodeOptions::clock_type(const rcl_clock_type_t & clock_type)
|
||||||
|
{
|
||||||
|
this->clock_type_ = clock_type;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
const rclcpp::QoS &
|
const rclcpp::QoS &
|
||||||
NodeOptions::clock_qos() const
|
NodeOptions::clock_qos() const
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ ParameterService::ParameterService(
|
|||||||
}
|
}
|
||||||
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
|
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
|
||||||
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to get parameters: %s", ex.what());
|
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to get parameters: %s", ex.what());
|
||||||
|
} catch (const rclcpp::exceptions::ParameterUninitializedException & ex) {
|
||||||
|
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp"), "Failed to get parameters: %s", ex.what());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
qos_profile, nullptr);
|
qos_profile, nullptr);
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
#include "rclcpp/network_flow_endpoint.hpp"
|
#include "rclcpp/network_flow_endpoint.hpp"
|
||||||
#include "rclcpp/node.hpp"
|
#include "rclcpp/node.hpp"
|
||||||
#include "rclcpp/qos_event.hpp"
|
#include "rclcpp/event_handler.hpp"
|
||||||
|
|
||||||
using rclcpp::PublisherBase;
|
using rclcpp::PublisherBase;
|
||||||
|
|
||||||
@@ -45,11 +45,14 @@ PublisherBase::PublisherBase(
|
|||||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||||
const std::string & topic,
|
const std::string & topic,
|
||||||
const rosidl_message_type_support_t & type_support,
|
const rosidl_message_type_support_t & type_support,
|
||||||
const rcl_publisher_options_t & publisher_options)
|
const rcl_publisher_options_t & publisher_options,
|
||||||
|
const PublisherEventCallbacks & event_callbacks,
|
||||||
|
bool use_default_callbacks)
|
||||||
: rcl_node_handle_(node_base->get_shared_rcl_node_handle()),
|
: rcl_node_handle_(node_base->get_shared_rcl_node_handle()),
|
||||||
intra_process_is_enabled_(false),
|
intra_process_is_enabled_(false),
|
||||||
intra_process_publisher_id_(0),
|
intra_process_publisher_id_(0),
|
||||||
type_support_(type_support)
|
type_support_(type_support),
|
||||||
|
event_callbacks_(event_callbacks)
|
||||||
{
|
{
|
||||||
auto custom_deleter = [node_handle = this->rcl_node_handle_](rcl_publisher_t * rcl_pub)
|
auto custom_deleter = [node_handle = this->rcl_node_handle_](rcl_publisher_t * rcl_pub)
|
||||||
{
|
{
|
||||||
@@ -98,15 +101,12 @@ PublisherBase::PublisherBase(
|
|||||||
rmw_reset_error();
|
rmw_reset_error();
|
||||||
throw std::runtime_error(msg);
|
throw std::runtime_error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bind_event_callbacks(event_callbacks_, use_default_callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
PublisherBase::~PublisherBase()
|
PublisherBase::~PublisherBase()
|
||||||
{
|
{
|
||||||
for (const auto & pair : event_handlers_) {
|
|
||||||
rcl_publisher_event_type_t event_type = pair.first;
|
|
||||||
clear_on_new_qos_event_callback(event_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// must fini the events before fini-ing the publisher
|
// must fini the events before fini-ing the publisher
|
||||||
event_handlers_.clear();
|
event_handlers_.clear();
|
||||||
|
|
||||||
@@ -131,6 +131,65 @@ PublisherBase::get_topic_name() const
|
|||||||
return rcl_publisher_get_topic_name(publisher_handle_.get());
|
return rcl_publisher_get_topic_name(publisher_handle_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PublisherBase::bind_event_callbacks(
|
||||||
|
const PublisherEventCallbacks & event_callbacks, bool use_default_callbacks)
|
||||||
|
{
|
||||||
|
if (event_callbacks.deadline_callback) {
|
||||||
|
this->add_event_handler(
|
||||||
|
event_callbacks.deadline_callback,
|
||||||
|
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
|
||||||
|
}
|
||||||
|
if (event_callbacks.liveliness_callback) {
|
||||||
|
this->add_event_handler(
|
||||||
|
event_callbacks.liveliness_callback,
|
||||||
|
RCL_PUBLISHER_LIVELINESS_LOST);
|
||||||
|
}
|
||||||
|
|
||||||
|
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_cb;
|
||||||
|
if (event_callbacks.incompatible_qos_callback) {
|
||||||
|
incompatible_qos_cb = event_callbacks.incompatible_qos_callback;
|
||||||
|
} else if (use_default_callbacks) {
|
||||||
|
// Register default callback when not specified
|
||||||
|
incompatible_qos_cb = [this](QOSOfferedIncompatibleQoSInfo & info) {
|
||||||
|
this->default_incompatible_qos_callback(info);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (incompatible_qos_cb) {
|
||||||
|
this->add_event_handler(incompatible_qos_cb, RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
||||||
|
}
|
||||||
|
} catch (const UnsupportedEventTypeException & /*exc*/) {
|
||||||
|
RCLCPP_DEBUG(
|
||||||
|
rclcpp::get_logger("rclcpp"),
|
||||||
|
"Failed to add event handler for incompatible qos; wrong callback type");
|
||||||
|
}
|
||||||
|
|
||||||
|
IncompatibleTypeCallbackType incompatible_type_cb;
|
||||||
|
if (event_callbacks.incompatible_type_callback) {
|
||||||
|
incompatible_type_cb = event_callbacks.incompatible_type_callback;
|
||||||
|
} else if (use_default_callbacks) {
|
||||||
|
// Register default callback when not specified
|
||||||
|
incompatible_type_cb = [this](IncompatibleTypeInfo & info) {
|
||||||
|
this->default_incompatible_type_callback(info);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (incompatible_type_cb) {
|
||||||
|
this->add_event_handler(incompatible_type_cb, RCL_PUBLISHER_INCOMPATIBLE_TYPE);
|
||||||
|
}
|
||||||
|
} catch (UnsupportedEventTypeException & /*exc*/) {
|
||||||
|
RCLCPP_DEBUG(
|
||||||
|
rclcpp::get_logger("rclcpp"),
|
||||||
|
"Failed to add event handler for incompatible type; wrong callback type");
|
||||||
|
}
|
||||||
|
if (event_callbacks.matched_callback) {
|
||||||
|
this->add_event_handler(
|
||||||
|
event_callbacks.matched_callback,
|
||||||
|
RCL_PUBLISHER_MATCHED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
PublisherBase::get_queue_size() const
|
PublisherBase::get_queue_size() const
|
||||||
{
|
{
|
||||||
@@ -163,7 +222,7 @@ PublisherBase::get_publisher_handle() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const
|
const
|
||||||
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
|
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
|
||||||
PublisherBase::get_event_handlers() const
|
PublisherBase::get_event_handlers() const
|
||||||
{
|
{
|
||||||
return event_handlers_;
|
return event_handlers_;
|
||||||
@@ -233,7 +292,7 @@ PublisherBase::assert_liveliness() const
|
|||||||
bool
|
bool
|
||||||
PublisherBase::can_loan_messages() const
|
PublisherBase::can_loan_messages() const
|
||||||
{
|
{
|
||||||
return rcl_publisher_can_loan_messages(publisher_handle_.get());
|
return !intra_process_is_enabled_ && rcl_publisher_can_loan_messages(publisher_handle_.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -279,6 +338,17 @@ PublisherBase::default_incompatible_qos_callback(
|
|||||||
policy_name.c_str());
|
policy_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
PublisherBase::default_incompatible_type_callback(
|
||||||
|
rclcpp::IncompatibleTypeInfo & event) const
|
||||||
|
{
|
||||||
|
(void)event;
|
||||||
|
|
||||||
|
RCLCPP_WARN(
|
||||||
|
rclcpp::get_logger(rcl_node_get_logger_name(rcl_node_handle_.get())),
|
||||||
|
"Incompatible type on topic '%s', no messages will be sent to it.", get_topic_name());
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<rclcpp::NetworkFlowEndpoint> PublisherBase::get_network_flow_endpoints() const
|
std::vector<rclcpp::NetworkFlowEndpoint> PublisherBase::get_network_flow_endpoints() const
|
||||||
{
|
{
|
||||||
rcutils_allocator_t allocator = rcutils_get_default_allocator();
|
rcutils_allocator_t allocator = rcutils_get_default_allocator();
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "rclcpp/logging.hpp"
|
||||||
|
|
||||||
#include "rmw/error_handling.h"
|
#include "rmw/error_handling.h"
|
||||||
#include "rmw/types.h"
|
#include "rmw/types.h"
|
||||||
#include "rmw/qos_profiles.h"
|
#include "rmw/qos_profiles.h"
|
||||||
@@ -43,9 +45,19 @@ std::string qos_policy_name_from_kind(rmw_qos_policy_kind_t policy_kind)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QoSInitialization::QoSInitialization(rmw_qos_history_policy_t history_policy_arg, size_t depth_arg)
|
QoSInitialization::QoSInitialization(
|
||||||
|
rmw_qos_history_policy_t history_policy_arg, size_t depth_arg,
|
||||||
|
bool print_depth_warning)
|
||||||
: history_policy(history_policy_arg), depth(depth_arg)
|
: history_policy(history_policy_arg), depth(depth_arg)
|
||||||
{}
|
{
|
||||||
|
if (history_policy == RMW_QOS_POLICY_HISTORY_KEEP_LAST && depth == 0 && print_depth_warning) {
|
||||||
|
RCLCPP_WARN_ONCE(
|
||||||
|
rclcpp::get_logger(
|
||||||
|
"rclcpp"),
|
||||||
|
"A zero depth with KEEP_LAST doesn't make sense; no data could be stored. "
|
||||||
|
"This will be interpreted as SYSTEM_DEFAULT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QoSInitialization
|
QoSInitialization
|
||||||
QoSInitialization::from_rmw(const rmw_qos_profile_t & rmw_qos)
|
QoSInitialization::from_rmw(const rmw_qos_profile_t & rmw_qos)
|
||||||
@@ -53,8 +65,9 @@ QoSInitialization::from_rmw(const rmw_qos_profile_t & rmw_qos)
|
|||||||
switch (rmw_qos.history) {
|
switch (rmw_qos.history) {
|
||||||
case RMW_QOS_POLICY_HISTORY_KEEP_ALL:
|
case RMW_QOS_POLICY_HISTORY_KEEP_ALL:
|
||||||
return KeepAll();
|
return KeepAll();
|
||||||
case RMW_QOS_POLICY_HISTORY_KEEP_LAST:
|
|
||||||
case RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT:
|
case RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT:
|
||||||
|
return KeepLast(rmw_qos.depth, false);
|
||||||
|
case RMW_QOS_POLICY_HISTORY_KEEP_LAST:
|
||||||
case RMW_QOS_POLICY_HISTORY_UNKNOWN:
|
case RMW_QOS_POLICY_HISTORY_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return KeepLast(rmw_qos.depth);
|
return KeepLast(rmw_qos.depth);
|
||||||
@@ -65,9 +78,10 @@ KeepAll::KeepAll()
|
|||||||
: QoSInitialization(RMW_QOS_POLICY_HISTORY_KEEP_ALL, 0)
|
: QoSInitialization(RMW_QOS_POLICY_HISTORY_KEEP_ALL, 0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
KeepLast::KeepLast(size_t depth)
|
KeepLast::KeepLast(size_t depth, bool print_depth_warning)
|
||||||
: QoSInitialization(RMW_QOS_POLICY_HISTORY_KEEP_LAST, depth)
|
: QoSInitialization(RMW_QOS_POLICY_HISTORY_KEEP_LAST, depth, print_depth_warning)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
QoS::QoS(
|
QoS::QoS(
|
||||||
const QoSInitialization & qos_initialization,
|
const QoSInitialization & qos_initialization,
|
||||||
@@ -111,6 +125,14 @@ QoS::history(HistoryPolicy history)
|
|||||||
QoS &
|
QoS &
|
||||||
QoS::keep_last(size_t depth)
|
QoS::keep_last(size_t depth)
|
||||||
{
|
{
|
||||||
|
if (depth == 0) {
|
||||||
|
RCLCPP_WARN_ONCE(
|
||||||
|
rclcpp::get_logger(
|
||||||
|
"rclcpp"),
|
||||||
|
"A zero depth with KEEP_LAST doesn't make sense; no data could be stored."
|
||||||
|
"This will be interpreted as SYSTEM_DEFAULT");
|
||||||
|
}
|
||||||
|
|
||||||
rmw_qos_profile_.history = RMW_QOS_POLICY_HISTORY_KEEP_LAST;
|
rmw_qos_profile_.history = RMW_QOS_POLICY_HISTORY_KEEP_LAST;
|
||||||
rmw_qos_profile_.depth = depth;
|
rmw_qos_profile_.depth = depth;
|
||||||
return *this;
|
return *this;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "rclcpp/any_service_callback.hpp"
|
#include "rclcpp/any_service_callback.hpp"
|
||||||
#include "rclcpp/macros.hpp"
|
#include "rclcpp/macros.hpp"
|
||||||
|
#include "rclcpp/qos.hpp"
|
||||||
#include "rmw/error_handling.h"
|
#include "rmw/error_handling.h"
|
||||||
#include "rmw/rmw.h"
|
#include "rmw/rmw.h"
|
||||||
|
|
||||||
@@ -32,10 +33,6 @@ ServiceBase::ServiceBase(std::shared_ptr<rcl_node_t> node_handle)
|
|||||||
node_logger_(rclcpp::get_node_logger(node_handle_.get()))
|
node_logger_(rclcpp::get_node_logger(node_handle_.get()))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ServiceBase::~ServiceBase()
|
|
||||||
{
|
|
||||||
clear_on_new_request_callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ServiceBase::take_type_erased_request(void * request_out, rmw_request_id_t & request_id_out)
|
ServiceBase::take_type_erased_request(void * request_out, rmw_request_id_t & request_id_out)
|
||||||
@@ -135,7 +132,7 @@ ServiceBase::set_on_new_request_callback(rcl_event_callback_t callback, const vo
|
|||||||
user_data);
|
user_data);
|
||||||
|
|
||||||
if (RCL_RET_OK != ret) {
|
if (RCL_RET_OK != ret) {
|
||||||
using rclcpp::exceptions::throw_from_rcl_error;
|
rclcpp::exceptions::throw_from_rcl_error(
|
||||||
throw_from_rcl_error(ret, "failed to set the on new request callback for service");
|
ret, "failed to set the on new request callback for service");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,9 @@ SignalHandler::uninstall()
|
|||||||
signal_handlers_options_ = SignalHandlerOptions::None;
|
signal_handlers_options_ = SignalHandlerOptions::None;
|
||||||
RCLCPP_DEBUG(get_logger(), "SignalHandler::uninstall(): notifying deferred signal handler");
|
RCLCPP_DEBUG(get_logger(), "SignalHandler::uninstall(): notifying deferred signal handler");
|
||||||
notify_signal_handler();
|
notify_signal_handler();
|
||||||
signal_handler_thread_.join();
|
if (signal_handler_thread_.joinable()) {
|
||||||
|
signal_handler_thread_.join();
|
||||||
|
}
|
||||||
teardown_wait_for_signal();
|
teardown_wait_for_signal();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
installed_.exchange(true);
|
installed_.exchange(true);
|
||||||
|
|||||||
@@ -22,16 +22,19 @@
|
|||||||
|
|
||||||
#include "rcpputils/scope_exit.hpp"
|
#include "rcpputils/scope_exit.hpp"
|
||||||
|
|
||||||
|
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||||
#include "rclcpp/exceptions.hpp"
|
#include "rclcpp/exceptions.hpp"
|
||||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||||
#include "rclcpp/experimental/intra_process_manager.hpp"
|
#include "rclcpp/experimental/intra_process_manager.hpp"
|
||||||
#include "rclcpp/logging.hpp"
|
#include "rclcpp/logging.hpp"
|
||||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||||
#include "rclcpp/qos_event.hpp"
|
#include "rclcpp/event_handler.hpp"
|
||||||
|
|
||||||
#include "rmw/error_handling.h"
|
#include "rmw/error_handling.h"
|
||||||
#include "rmw/rmw.h"
|
#include "rmw/rmw.h"
|
||||||
|
|
||||||
|
#include "rosidl_dynamic_typesupport/types.h"
|
||||||
|
|
||||||
using rclcpp::SubscriptionBase;
|
using rclcpp::SubscriptionBase;
|
||||||
|
|
||||||
SubscriptionBase::SubscriptionBase(
|
SubscriptionBase::SubscriptionBase(
|
||||||
@@ -39,15 +42,26 @@ SubscriptionBase::SubscriptionBase(
|
|||||||
const rosidl_message_type_support_t & type_support_handle,
|
const rosidl_message_type_support_t & type_support_handle,
|
||||||
const std::string & topic_name,
|
const std::string & topic_name,
|
||||||
const rcl_subscription_options_t & subscription_options,
|
const rcl_subscription_options_t & subscription_options,
|
||||||
bool is_serialized)
|
const SubscriptionEventCallbacks & event_callbacks,
|
||||||
|
bool use_default_callbacks,
|
||||||
|
SubscriptionType subscription_type)
|
||||||
: node_base_(node_base),
|
: node_base_(node_base),
|
||||||
node_handle_(node_base_->get_shared_rcl_node_handle()),
|
node_handle_(node_base_->get_shared_rcl_node_handle()),
|
||||||
node_logger_(rclcpp::get_node_logger(node_handle_.get())),
|
node_logger_(rclcpp::get_node_logger(node_handle_.get())),
|
||||||
use_intra_process_(false),
|
use_intra_process_(false),
|
||||||
intra_process_subscription_id_(0),
|
intra_process_subscription_id_(0),
|
||||||
|
event_callbacks_(event_callbacks),
|
||||||
type_support_(type_support_handle),
|
type_support_(type_support_handle),
|
||||||
is_serialized_(is_serialized)
|
subscription_type_(subscription_type)
|
||||||
{
|
{
|
||||||
|
if (!rmw_feature_supported(RMW_MIDDLEWARE_CAN_TAKE_DYNAMIC_MESSAGE) &&
|
||||||
|
subscription_type == rclcpp::SubscriptionType::DYNAMIC_MESSAGE_DIRECT)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Cannot set subscription to take dynamic message directly, feature not supported in rmw"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
auto custom_deletor = [node_handle = this->node_handle_](rcl_subscription_t * rcl_subs)
|
auto custom_deletor = [node_handle = this->node_handle_](rcl_subscription_t * rcl_subs)
|
||||||
{
|
{
|
||||||
if (rcl_subscription_fini(rcl_subs, node_handle.get()) != RCL_RET_OK) {
|
if (rcl_subscription_fini(rcl_subs, node_handle.get()) != RCL_RET_OK) {
|
||||||
@@ -80,20 +94,14 @@ SubscriptionBase::SubscriptionBase(
|
|||||||
rcl_node_get_name(rcl_node_handle),
|
rcl_node_get_name(rcl_node_handle),
|
||||||
rcl_node_get_namespace(rcl_node_handle));
|
rcl_node_get_namespace(rcl_node_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create subscription");
|
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create subscription");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bind_event_callbacks(event_callbacks_, use_default_callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
SubscriptionBase::~SubscriptionBase()
|
SubscriptionBase::~SubscriptionBase()
|
||||||
{
|
{
|
||||||
clear_on_new_message_callback();
|
|
||||||
|
|
||||||
for (const auto & pair : event_handlers_) {
|
|
||||||
rcl_subscription_event_type_t event_type = pair.first;
|
|
||||||
clear_on_new_qos_event_callback(event_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!use_intra_process_) {
|
if (!use_intra_process_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -108,6 +116,69 @@ SubscriptionBase::~SubscriptionBase()
|
|||||||
ipm->remove_subscription(intra_process_subscription_id_);
|
ipm->remove_subscription(intra_process_subscription_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SubscriptionBase::bind_event_callbacks(
|
||||||
|
const SubscriptionEventCallbacks & event_callbacks, bool use_default_callbacks)
|
||||||
|
{
|
||||||
|
if (event_callbacks.deadline_callback) {
|
||||||
|
this->add_event_handler(
|
||||||
|
event_callbacks.deadline_callback,
|
||||||
|
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_callbacks.liveliness_callback) {
|
||||||
|
this->add_event_handler(
|
||||||
|
event_callbacks.liveliness_callback,
|
||||||
|
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_cb;
|
||||||
|
if (event_callbacks.incompatible_qos_callback) {
|
||||||
|
incompatible_qos_cb = event_callbacks.incompatible_qos_callback;
|
||||||
|
} else if (use_default_callbacks) {
|
||||||
|
// Register default callback when not specified
|
||||||
|
incompatible_qos_cb = [this](QOSRequestedIncompatibleQoSInfo & info) {
|
||||||
|
this->default_incompatible_qos_callback(info);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Register default callback when not specified
|
||||||
|
try {
|
||||||
|
if (incompatible_qos_cb) {
|
||||||
|
this->add_event_handler(incompatible_qos_cb, RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
|
||||||
|
}
|
||||||
|
} catch (const UnsupportedEventTypeException & /*exc*/) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
|
||||||
|
IncompatibleTypeCallbackType incompatible_type_cb;
|
||||||
|
if (event_callbacks.incompatible_type_callback) {
|
||||||
|
incompatible_type_cb = event_callbacks.incompatible_type_callback;
|
||||||
|
} else if (use_default_callbacks) {
|
||||||
|
// Register default callback when not specified
|
||||||
|
incompatible_type_cb = [this](IncompatibleTypeInfo & info) {
|
||||||
|
this->default_incompatible_type_callback(info);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (incompatible_type_cb) {
|
||||||
|
this->add_event_handler(incompatible_type_cb, RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE);
|
||||||
|
}
|
||||||
|
} catch (UnsupportedEventTypeException & /*exc*/) {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_callbacks.message_lost_callback) {
|
||||||
|
this->add_event_handler(
|
||||||
|
event_callbacks.message_lost_callback,
|
||||||
|
RCL_SUBSCRIPTION_MESSAGE_LOST);
|
||||||
|
}
|
||||||
|
if (event_callbacks.matched_callback) {
|
||||||
|
this->add_event_handler(
|
||||||
|
event_callbacks.matched_callback,
|
||||||
|
RCL_SUBSCRIPTION_MATCHED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char *
|
const char *
|
||||||
SubscriptionBase::get_topic_name() const
|
SubscriptionBase::get_topic_name() const
|
||||||
{
|
{
|
||||||
@@ -127,7 +198,7 @@ SubscriptionBase::get_subscription_handle() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
const
|
const
|
||||||
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
|
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
|
||||||
SubscriptionBase::get_event_handlers() const
|
SubscriptionBase::get_event_handlers() const
|
||||||
{
|
{
|
||||||
return event_handlers_;
|
return event_handlers_;
|
||||||
@@ -195,10 +266,10 @@ SubscriptionBase::get_message_type_support_handle() const
|
|||||||
return type_support_;
|
return type_support_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
rclcpp::SubscriptionType
|
||||||
SubscriptionBase::is_serialized() const
|
SubscriptionBase::get_subscription_type() const
|
||||||
{
|
{
|
||||||
return is_serialized_;
|
return subscription_type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
@@ -265,6 +336,17 @@ SubscriptionBase::default_incompatible_qos_callback(
|
|||||||
policy_name.c_str());
|
policy_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SubscriptionBase::default_incompatible_type_callback(
|
||||||
|
rclcpp::IncompatibleTypeInfo & event) const
|
||||||
|
{
|
||||||
|
(void)event;
|
||||||
|
|
||||||
|
RCLCPP_WARN(
|
||||||
|
rclcpp::get_logger(rcl_node_get_logger_name(node_handle_.get())),
|
||||||
|
"Incompatible type on topic '%s', no messages will be sent to it.", get_topic_name());
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
SubscriptionBase::matches_any_intra_process_publishers(const rmw_gid_t * sender_gid) const
|
SubscriptionBase::matches_any_intra_process_publishers(const rmw_gid_t * sender_gid) const
|
||||||
{
|
{
|
||||||
@@ -371,8 +453,7 @@ SubscriptionBase::set_content_filter(
|
|||||||
rcl_subscription_content_filter_options_t options =
|
rcl_subscription_content_filter_options_t options =
|
||||||
rcl_get_zero_initialized_subscription_content_filter_options();
|
rcl_get_zero_initialized_subscription_content_filter_options();
|
||||||
|
|
||||||
std::vector<const char *> cstrings =
|
std::vector<const char *> cstrings = get_c_vector_string(expression_parameters);
|
||||||
get_c_vector_string(expression_parameters);
|
|
||||||
rcl_ret_t ret = rcl_subscription_content_filter_options_init(
|
rcl_ret_t ret = rcl_subscription_content_filter_options_init(
|
||||||
subscription_handle_.get(),
|
subscription_handle_.get(),
|
||||||
get_c_string(filter_expression),
|
get_c_string(filter_expression),
|
||||||
@@ -444,3 +525,24 @@ SubscriptionBase::get_content_filter() const
|
|||||||
|
|
||||||
return ret_options;
|
return ret_options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// DYNAMIC TYPE ==================================================================================
|
||||||
|
// TODO(methylDragon): Reorder later
|
||||||
|
bool
|
||||||
|
SubscriptionBase::take_dynamic_message(
|
||||||
|
rclcpp::dynamic_typesupport::DynamicMessage & message_out,
|
||||||
|
rclcpp::MessageInfo & message_info_out)
|
||||||
|
{
|
||||||
|
rcl_ret_t ret = rcl_take_dynamic_message(
|
||||||
|
this->get_subscription_handle().get(),
|
||||||
|
&message_out.get_rosidl_dynamic_data(),
|
||||||
|
&message_info_out.get_rmw_message_info(),
|
||||||
|
nullptr);
|
||||||
|
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
|
||||||
|
return false;
|
||||||
|
} else if (RCL_RET_OK != ret) {
|
||||||
|
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,11 +17,6 @@
|
|||||||
|
|
||||||
using rclcpp::experimental::SubscriptionIntraProcessBase;
|
using rclcpp::experimental::SubscriptionIntraProcessBase;
|
||||||
|
|
||||||
SubscriptionIntraProcessBase::~SubscriptionIntraProcessBase()
|
|
||||||
{
|
|
||||||
clear_on_ready_callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
SubscriptionIntraProcessBase::add_to_wait_set(rcl_wait_set_t * wait_set)
|
SubscriptionIntraProcessBase::add_to_wait_set(rcl_wait_set_t * wait_set)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ class ClocksState final
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClocksState()
|
ClocksState()
|
||||||
: logger_(rclcpp::get_logger("rclcpp"))
|
: logger_(rclcpp::get_logger("rclcpp")),
|
||||||
|
last_time_msg_(std::make_shared<builtin_interfaces::msg::Time>())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,13 +54,8 @@ public:
|
|||||||
ros_time_active_ = true;
|
ros_time_active_ = true;
|
||||||
|
|
||||||
// Update all attached clocks to zero or last recorded time
|
// Update all attached clocks to zero or last recorded time
|
||||||
std::lock_guard<std::mutex> guard(clock_list_lock_);
|
|
||||||
auto time_msg = std::make_shared<builtin_interfaces::msg::Time>();
|
|
||||||
if (last_msg_set_) {
|
|
||||||
time_msg = std::make_shared<builtin_interfaces::msg::Time>(last_msg_set_->clock);
|
|
||||||
}
|
|
||||||
for (auto it = associated_clocks_.begin(); it != associated_clocks_.end(); ++it) {
|
for (auto it = associated_clocks_.begin(); it != associated_clocks_.end(); ++it) {
|
||||||
set_clock(time_msg, true, *it);
|
set_clock(last_time_msg_, true, *it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,18 +87,17 @@ public:
|
|||||||
// Attach a clock
|
// Attach a clock
|
||||||
void attachClock(rclcpp::Clock::SharedPtr clock)
|
void attachClock(rclcpp::Clock::SharedPtr clock)
|
||||||
{
|
{
|
||||||
if (clock->get_clock_type() != RCL_ROS_TIME) {
|
{
|
||||||
throw std::invalid_argument("Cannot attach clock to a time source that's not a ROS clock");
|
std::lock_guard<std::mutex> clock_guard(clock->get_clock_mutex());
|
||||||
|
if (clock->get_clock_type() != RCL_ROS_TIME && ros_time_active_) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"ros_time_active_ can't be true while clock is not of RCL_ROS_TIME type");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> guard(clock_list_lock_);
|
std::lock_guard<std::mutex> guard(clock_list_lock_);
|
||||||
associated_clocks_.push_back(clock);
|
associated_clocks_.push_back(clock);
|
||||||
// Set the clock to zero unless there's a recently received message
|
// Set the clock to zero unless there's a recently received message
|
||||||
auto time_msg = std::make_shared<builtin_interfaces::msg::Time>();
|
set_clock(last_time_msg_, ros_time_active_, clock);
|
||||||
if (last_msg_set_) {
|
|
||||||
time_msg = std::make_shared<builtin_interfaces::msg::Time>(last_msg_set_->clock);
|
|
||||||
}
|
|
||||||
set_clock(time_msg, ros_time_active_, clock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detach a clock
|
// Detach a clock
|
||||||
@@ -125,27 +120,32 @@ public:
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> clock_guard(clock->get_clock_mutex());
|
std::lock_guard<std::mutex> clock_guard(clock->get_clock_mutex());
|
||||||
|
|
||||||
// Do change
|
if (clock->get_clock_type() == RCL_ROS_TIME) {
|
||||||
if (!set_ros_time_enabled && clock->ros_time_is_active()) {
|
// Do change
|
||||||
auto ret = rcl_disable_ros_time_override(clock->get_clock_handle());
|
if (!set_ros_time_enabled && clock->ros_time_is_active()) {
|
||||||
if (ret != RCL_RET_OK) {
|
auto ret = rcl_disable_ros_time_override(clock->get_clock_handle());
|
||||||
rclcpp::exceptions::throw_from_rcl_error(
|
if (ret != RCL_RET_OK) {
|
||||||
ret, "Failed to disable ros_time_override_status");
|
rclcpp::exceptions::throw_from_rcl_error(
|
||||||
|
ret, "Failed to disable ros_time_override_status");
|
||||||
|
}
|
||||||
|
} else if (set_ros_time_enabled && !clock->ros_time_is_active()) {
|
||||||
|
auto ret = rcl_enable_ros_time_override(clock->get_clock_handle());
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
rclcpp::exceptions::throw_from_rcl_error(
|
||||||
|
ret, "Failed to enable ros_time_override_status");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (set_ros_time_enabled && !clock->ros_time_is_active()) {
|
|
||||||
auto ret = rcl_enable_ros_time_override(clock->get_clock_handle());
|
|
||||||
if (ret != RCL_RET_OK) {
|
|
||||||
rclcpp::exceptions::throw_from_rcl_error(
|
|
||||||
ret, "Failed to enable ros_time_override_status");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ret = rcl_set_ros_time_override(
|
auto ret = rcl_set_ros_time_override(
|
||||||
clock->get_clock_handle(),
|
clock->get_clock_handle(),
|
||||||
rclcpp::Time(*msg).nanoseconds());
|
rclcpp::Time(*msg).nanoseconds());
|
||||||
if (ret != RCL_RET_OK) {
|
if (ret != RCL_RET_OK) {
|
||||||
rclcpp::exceptions::throw_from_rcl_error(
|
rclcpp::exceptions::throw_from_rcl_error(
|
||||||
ret, "Failed to set ros_time_override_status");
|
ret, "Failed to set ros_time_override_status");
|
||||||
|
}
|
||||||
|
} else if (set_ros_time_enabled) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"set_ros_time_enabled can't be true while clock is not of RCL_ROS_TIME type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +163,19 @@ public:
|
|||||||
// Cache the last clock message received
|
// Cache the last clock message received
|
||||||
void cache_last_msg(std::shared_ptr<const rosgraph_msgs::msg::Clock> msg)
|
void cache_last_msg(std::shared_ptr<const rosgraph_msgs::msg::Clock> msg)
|
||||||
{
|
{
|
||||||
last_msg_set_ = msg;
|
last_time_msg_ = std::make_shared<builtin_interfaces::msg::Time>(msg->clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool are_all_clocks_rcl_ros_time()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard(clock_list_lock_);
|
||||||
|
for (auto & clock : associated_clocks_) {
|
||||||
|
std::lock_guard<std::mutex> clock_guard(clock->get_clock_mutex());
|
||||||
|
if (clock->get_clock_type() != RCL_ROS_TIME) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -179,7 +191,7 @@ private:
|
|||||||
// This is needed when new clocks are added.
|
// This is needed when new clocks are added.
|
||||||
bool ros_time_active_{false};
|
bool ros_time_active_{false};
|
||||||
// Last set message to be passed to newly registered clocks
|
// Last set message to be passed to newly registered clocks
|
||||||
std::shared_ptr<const rosgraph_msgs::msg::Clock> last_msg_set_;
|
std::shared_ptr<builtin_interfaces::msg::Time> last_time_msg_{nullptr};
|
||||||
};
|
};
|
||||||
|
|
||||||
class TimeSource::NodeState final
|
class TimeSource::NodeState final
|
||||||
@@ -266,6 +278,10 @@ public:
|
|||||||
throw std::invalid_argument("Invalid type for parameter 'use_sim_time', should be 'bool'");
|
throw std::invalid_argument("Invalid type for parameter 'use_sim_time', should be 'bool'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
on_set_parameters_callback_ = node_parameters_->add_on_set_parameters_callback(
|
||||||
|
std::bind(&TimeSource::NodeState::on_set_parameters, this, std::placeholders::_1));
|
||||||
|
|
||||||
|
|
||||||
// TODO(tfoote) use parameters interface not subscribe to events via topic ticketed #609
|
// TODO(tfoote) use parameters interface not subscribe to events via topic ticketed #609
|
||||||
parameter_subscription_ = rclcpp::AsyncParametersClient::on_parameter_event(
|
parameter_subscription_ = rclcpp::AsyncParametersClient::on_parameter_event(
|
||||||
node_topics_,
|
node_topics_,
|
||||||
@@ -285,6 +301,10 @@ public:
|
|||||||
// can't possibly call any of the callbacks as we are cleaning up.
|
// can't possibly call any of the callbacks as we are cleaning up.
|
||||||
destroy_clock_sub();
|
destroy_clock_sub();
|
||||||
clocks_state_.disable_ros_time();
|
clocks_state_.disable_ros_time();
|
||||||
|
if (on_set_parameters_callback_) {
|
||||||
|
node_parameters_->remove_on_set_parameters_callback(on_set_parameters_callback_.get());
|
||||||
|
}
|
||||||
|
on_set_parameters_callback_.reset();
|
||||||
parameter_subscription_.reset();
|
parameter_subscription_.reset();
|
||||||
node_base_.reset();
|
node_base_.reset();
|
||||||
node_topics_.reset();
|
node_topics_.reset();
|
||||||
@@ -419,10 +439,34 @@ private:
|
|||||||
clock_subscription_.reset();
|
clock_subscription_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On set Parameters callback handle
|
||||||
|
node_interfaces::OnSetParametersCallbackHandle::SharedPtr on_set_parameters_callback_{nullptr};
|
||||||
|
|
||||||
// Parameter Event subscription
|
// Parameter Event subscription
|
||||||
using ParamSubscriptionT = rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>;
|
using ParamSubscriptionT = rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>;
|
||||||
std::shared_ptr<ParamSubscriptionT> parameter_subscription_;
|
std::shared_ptr<ParamSubscriptionT> parameter_subscription_;
|
||||||
|
|
||||||
|
// Callback for parameter settings
|
||||||
|
rcl_interfaces::msg::SetParametersResult on_set_parameters(
|
||||||
|
const std::vector<rclcpp::Parameter> & parameters)
|
||||||
|
{
|
||||||
|
rcl_interfaces::msg::SetParametersResult result;
|
||||||
|
result.successful = true;
|
||||||
|
for (const auto & param : parameters) {
|
||||||
|
if (param.get_name() == "use_sim_time" && param.get_type() == rclcpp::PARAMETER_BOOL) {
|
||||||
|
if (param.as_bool() && !(clocks_state_.are_all_clocks_rcl_ros_time())) {
|
||||||
|
result.successful = false;
|
||||||
|
result.reason =
|
||||||
|
"use_sim_time parameter can't be true while clocks are not all of RCL_ROS_TIME type";
|
||||||
|
RCLCPP_ERROR(
|
||||||
|
logger_,
|
||||||
|
"use_sim_time parameter can't be true while clocks are not all of RCL_ROS_TIME type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// Callback for parameter updates
|
// Callback for parameter updates
|
||||||
void on_parameter_event(std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event)
|
void on_parameter_event(std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,9 +19,12 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "rclcpp/contexts/default_context.hpp"
|
#include "rmw/impl/cpp/demangle.hpp"
|
||||||
#include "rclcpp/exceptions.hpp"
|
|
||||||
|
|
||||||
|
#include "rclcpp/contexts/default_context.hpp"
|
||||||
|
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||||
|
#include "rclcpp/exceptions.hpp"
|
||||||
|
#include "rclcpp/logging.hpp"
|
||||||
#include "rcutils/logging_macros.h"
|
#include "rcutils/logging_macros.h"
|
||||||
|
|
||||||
using rclcpp::TimerBase;
|
using rclcpp::TimerBase;
|
||||||
@@ -71,7 +74,9 @@ TimerBase::TimerBase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
TimerBase::~TimerBase()
|
TimerBase::~TimerBase()
|
||||||
{}
|
{
|
||||||
|
clear_on_reset_callback();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
TimerBase::cancel()
|
TimerBase::cancel()
|
||||||
@@ -96,7 +101,11 @@ TimerBase::is_canceled()
|
|||||||
void
|
void
|
||||||
TimerBase::reset()
|
TimerBase::reset()
|
||||||
{
|
{
|
||||||
rcl_ret_t ret = rcl_timer_reset(timer_handle_.get());
|
rcl_ret_t ret = RCL_RET_OK;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||||
|
ret = rcl_timer_reset(timer_handle_.get());
|
||||||
|
}
|
||||||
if (ret != RCL_RET_OK) {
|
if (ret != RCL_RET_OK) {
|
||||||
rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't reset timer");
|
rclcpp::exceptions::throw_from_rcl_error(ret, "Couldn't reset timer");
|
||||||
}
|
}
|
||||||
@@ -138,3 +147,73 @@ TimerBase::exchange_in_use_by_wait_set_state(bool in_use_state)
|
|||||||
{
|
{
|
||||||
return in_use_by_wait_set_.exchange(in_use_state);
|
return in_use_by_wait_set_.exchange(in_use_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimerBase::set_on_reset_callback(std::function<void(size_t)> callback)
|
||||||
|
{
|
||||||
|
if (!callback) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"The callback passed to set_on_reset_callback "
|
||||||
|
"is not callable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto new_callback =
|
||||||
|
[callback, this](size_t reset_calls) {
|
||||||
|
try {
|
||||||
|
callback(reset_calls);
|
||||||
|
} catch (const std::exception & exception) {
|
||||||
|
RCLCPP_ERROR_STREAM(
|
||||||
|
rclcpp::get_logger("rclcpp"),
|
||||||
|
"rclcpp::TimerBase@" << this <<
|
||||||
|
" caught " << rmw::impl::cpp::demangle(exception) <<
|
||||||
|
" exception in user-provided callback for the 'on reset' callback: " <<
|
||||||
|
exception.what());
|
||||||
|
} catch (...) {
|
||||||
|
RCLCPP_ERROR_STREAM(
|
||||||
|
rclcpp::get_logger("rclcpp"),
|
||||||
|
"rclcpp::TimerBase@" << this <<
|
||||||
|
" caught unhandled exception in user-provided callback " <<
|
||||||
|
"for the 'on reset' callback");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||||
|
|
||||||
|
// Set it temporarily to the new callback, while we replace the old one.
|
||||||
|
// This two-step setting, prevents a gap where the old std::function has
|
||||||
|
// been replaced but rcl hasn't been told about the new one yet.
|
||||||
|
set_on_reset_callback(
|
||||||
|
rclcpp::detail::cpp_callback_trampoline<
|
||||||
|
decltype(new_callback), const void *, size_t>,
|
||||||
|
static_cast<const void *>(&new_callback));
|
||||||
|
|
||||||
|
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||||
|
on_reset_callback_ = new_callback;
|
||||||
|
|
||||||
|
// Set it again, now using the permanent storage.
|
||||||
|
set_on_reset_callback(
|
||||||
|
rclcpp::detail::cpp_callback_trampoline<
|
||||||
|
decltype(on_reset_callback_), const void *, size_t>,
|
||||||
|
static_cast<const void *>(&on_reset_callback_));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimerBase::clear_on_reset_callback()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||||
|
|
||||||
|
if (on_reset_callback_) {
|
||||||
|
set_on_reset_callback(nullptr, nullptr);
|
||||||
|
on_reset_callback_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TimerBase::set_on_reset_callback(rcl_event_callback_t callback, const void * user_data)
|
||||||
|
{
|
||||||
|
rcl_ret_t ret = rcl_timer_set_on_reset_callback(timer_handle_.get(), callback, user_data);
|
||||||
|
|
||||||
|
if (ret != RCL_RET_OK) {
|
||||||
|
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to set timer on reset callback");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -100,15 +100,20 @@ if(TARGET test_create_subscription)
|
|||||||
"test_msgs"
|
"test_msgs"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
ament_add_gtest(test_add_callback_groups_to_executor
|
function(test_add_callback_groups_to_executor_for_rmw_implementation)
|
||||||
test_add_callback_groups_to_executor.cpp
|
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
|
||||||
TIMEOUT 120)
|
ament_add_gmock(test_add_callback_groups_to_executor${target_suffix} test_add_callback_groups_to_executor.cpp
|
||||||
if(TARGET test_add_callback_groups_to_executor)
|
ENV ${rmw_implementation_env_var}
|
||||||
target_link_libraries(test_add_callback_groups_to_executor ${PROJECT_NAME})
|
TIMEOUT 120
|
||||||
ament_target_dependencies(test_add_callback_groups_to_executor
|
|
||||||
"test_msgs"
|
|
||||||
)
|
)
|
||||||
endif()
|
if(TARGET test_add_callback_groups_to_executor${target_suffix})
|
||||||
|
target_link_libraries(test_add_callback_groups_to_executor${target_suffix} ${PROJECT_NAME})
|
||||||
|
ament_target_dependencies(test_add_callback_groups_to_executor${target_suffix}
|
||||||
|
"test_msgs"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
call_for_each_rmw_implementation(test_add_callback_groups_to_executor_for_rmw_implementation)
|
||||||
ament_add_gtest(test_expand_topic_or_service_name test_expand_topic_or_service_name.cpp)
|
ament_add_gtest(test_expand_topic_or_service_name test_expand_topic_or_service_name.cpp)
|
||||||
if(TARGET test_expand_topic_or_service_name)
|
if(TARGET test_expand_topic_or_service_name)
|
||||||
ament_target_dependencies(test_expand_topic_or_service_name
|
ament_target_dependencies(test_expand_topic_or_service_name
|
||||||
@@ -229,6 +234,11 @@ if(TARGET test_node_interfaces__node_graph)
|
|||||||
"test_msgs")
|
"test_msgs")
|
||||||
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME} mimick)
|
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME} mimick)
|
||||||
endif()
|
endif()
|
||||||
|
ament_add_gtest(test_node_interfaces__node_interfaces
|
||||||
|
node_interfaces/test_node_interfaces.cpp)
|
||||||
|
if(TARGET test_node_interfaces__node_interfaces)
|
||||||
|
target_link_libraries(test_node_interfaces__node_interfaces ${PROJECT_NAME} mimick)
|
||||||
|
endif()
|
||||||
ament_add_gtest(test_node_interfaces__node_parameters
|
ament_add_gtest(test_node_interfaces__node_parameters
|
||||||
node_interfaces/test_node_parameters.cpp)
|
node_interfaces/test_node_parameters.cpp)
|
||||||
if(TARGET test_node_interfaces__node_parameters)
|
if(TARGET test_node_interfaces__node_parameters)
|
||||||
@@ -257,6 +267,11 @@ ament_add_gtest(test_node_interfaces__node_waitables
|
|||||||
if(TARGET test_node_interfaces__node_waitables)
|
if(TARGET test_node_interfaces__node_waitables)
|
||||||
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME} mimick)
|
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME} mimick)
|
||||||
endif()
|
endif()
|
||||||
|
ament_add_gtest(test_node_interfaces__test_template_utils # Compile time test
|
||||||
|
node_interfaces/detail/test_template_utils.cpp)
|
||||||
|
if(TARGET test_node_interfaces__test_template_utils)
|
||||||
|
target_link_libraries(test_node_interfaces__test_template_utils ${PROJECT_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
# TODO(wjwwood): reenable these build failure tests when I can get Jenkins to ignore their output
|
# TODO(wjwwood): reenable these build failure tests when I can get Jenkins to ignore their output
|
||||||
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_rclcpp_node
|
# rclcpp_add_build_failure_test(build_failure__get_node_topics_interface_const_ref_rclcpp_node
|
||||||
@@ -429,17 +444,23 @@ function(test_generic_pubsub_for_rmw_implementation)
|
|||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
call_for_each_rmw_implementation(test_generic_pubsub_for_rmw_implementation)
|
call_for_each_rmw_implementation(test_generic_pubsub_for_rmw_implementation)
|
||||||
ament_add_gtest(test_qos_event test_qos_event.cpp)
|
|
||||||
if(TARGET test_qos_event)
|
function(test_qos_event_for_rmw_implementation)
|
||||||
ament_target_dependencies(test_qos_event
|
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
|
||||||
"rmw"
|
ament_add_gmock(test_qos_event${target_suffix} test_qos_event.cpp
|
||||||
"test_msgs"
|
ENV ${rmw_implementation_env_var}
|
||||||
)
|
)
|
||||||
target_link_libraries(test_qos_event
|
if(TARGET test_qos_event${target_suffix})
|
||||||
${PROJECT_NAME}
|
target_link_libraries(test_qos_event${target_suffix} ${PROJECT_NAME} mimick)
|
||||||
mimick
|
ament_target_dependencies(test_qos_event${target_suffix}
|
||||||
)
|
"rmw"
|
||||||
endif()
|
"rosidl_typesupport_cpp"
|
||||||
|
"test_msgs"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endfunction()
|
||||||
|
call_for_each_rmw_implementation(test_qos_event_for_rmw_implementation)
|
||||||
|
|
||||||
ament_add_gmock(test_qos_overriding_options test_qos_overriding_options.cpp)
|
ament_add_gmock(test_qos_overriding_options test_qos_overriding_options.cpp)
|
||||||
if(TARGET test_qos_overriding_options)
|
if(TARGET test_qos_overriding_options)
|
||||||
target_link_libraries(test_qos_overriding_options
|
target_link_libraries(test_qos_overriding_options
|
||||||
@@ -493,6 +514,17 @@ if(TARGET test_service)
|
|||||||
)
|
)
|
||||||
target_link_libraries(test_service ${PROJECT_NAME} mimick)
|
target_link_libraries(test_service ${PROJECT_NAME} mimick)
|
||||||
endif()
|
endif()
|
||||||
|
ament_add_gmock(test_service_introspection test_service_introspection.cpp)
|
||||||
|
if(TARGET test_service)
|
||||||
|
ament_target_dependencies(test_service_introspection
|
||||||
|
"rcl_interfaces"
|
||||||
|
"rmw"
|
||||||
|
"rosidl_runtime_cpp"
|
||||||
|
"rosidl_typesupport_cpp"
|
||||||
|
"test_msgs"
|
||||||
|
)
|
||||||
|
target_link_libraries(test_service_introspection ${PROJECT_NAME} mimick)
|
||||||
|
endif()
|
||||||
# Creating and destroying nodes is slow with Connext, so this needs larger timeout.
|
# Creating and destroying nodes is slow with Connext, so this needs larger timeout.
|
||||||
ament_add_gtest(test_subscription test_subscription.cpp TIMEOUT 120)
|
ament_add_gtest(test_subscription test_subscription.cpp TIMEOUT 120)
|
||||||
if(TARGET test_subscription)
|
if(TARGET test_subscription)
|
||||||
@@ -567,6 +599,9 @@ target_link_libraries(test_logger ${PROJECT_NAME})
|
|||||||
ament_add_gmock(test_logging test_logging.cpp)
|
ament_add_gmock(test_logging test_logging.cpp)
|
||||||
target_link_libraries(test_logging ${PROJECT_NAME})
|
target_link_libraries(test_logging ${PROJECT_NAME})
|
||||||
|
|
||||||
|
ament_add_gmock(test_context test_context.cpp)
|
||||||
|
target_link_libraries(test_context ${PROJECT_NAME})
|
||||||
|
|
||||||
ament_add_gtest(test_time test_time.cpp
|
ament_add_gtest(test_time test_time.cpp
|
||||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||||
if(TARGET test_time)
|
if(TARGET test_time)
|
||||||
@@ -721,6 +756,12 @@ if(TARGET test_rosout_qos)
|
|||||||
target_link_libraries(test_rosout_qos ${PROJECT_NAME})
|
target_link_libraries(test_rosout_qos ${PROJECT_NAME})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
ament_add_gtest(test_rosout_subscription test_rosout_subscription.cpp)
|
||||||
|
if(TARGET test_rosout_subscription)
|
||||||
|
ament_target_dependencies(test_rosout_subscription "rcl")
|
||||||
|
target_link_libraries(test_rosout_subscription ${PROJECT_NAME})
|
||||||
|
endif()
|
||||||
|
|
||||||
ament_add_gtest(test_executor test_executor.cpp
|
ament_add_gtest(test_executor test_executor.cpp
|
||||||
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
||||||
TIMEOUT 120)
|
TIMEOUT 120)
|
||||||
|
|||||||
@@ -51,6 +51,53 @@ TEST(TestAllocatorCommon, retyped_allocate) {
|
|||||||
EXPECT_NO_THROW(code2());
|
EXPECT_NO_THROW(code2());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(TestAllocatorCommon, retyped_zero_allocate_basic) {
|
||||||
|
std::allocator<int> allocator;
|
||||||
|
void * untyped_allocator = &allocator;
|
||||||
|
void * allocated_mem =
|
||||||
|
rclcpp::allocator::retyped_zero_allocate<std::allocator<char>>(20u, 1u, untyped_allocator);
|
||||||
|
ASSERT_TRUE(nullptr != allocated_mem);
|
||||||
|
|
||||||
|
auto code = [&untyped_allocator, allocated_mem]() {
|
||||||
|
rclcpp::allocator::retyped_deallocate<char, std::allocator<char>>(
|
||||||
|
allocated_mem, untyped_allocator);
|
||||||
|
};
|
||||||
|
EXPECT_NO_THROW(code());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(TestAllocatorCommon, retyped_zero_allocate) {
|
||||||
|
std::allocator<int> allocator;
|
||||||
|
void * untyped_allocator = &allocator;
|
||||||
|
void * allocated_mem =
|
||||||
|
rclcpp::allocator::retyped_zero_allocate<std::allocator<char>>(20u, 1u, untyped_allocator);
|
||||||
|
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
|
||||||
|
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
|
||||||
|
ASSERT_TRUE(nullptr != allocated_mem);
|
||||||
|
|
||||||
|
auto code = [&untyped_allocator, allocated_mem]() {
|
||||||
|
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
|
||||||
|
allocated_mem, untyped_allocator);
|
||||||
|
};
|
||||||
|
EXPECT_NO_THROW(code());
|
||||||
|
|
||||||
|
allocated_mem = allocator.allocate(1);
|
||||||
|
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
|
||||||
|
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
|
||||||
|
ASSERT_TRUE(nullptr != allocated_mem);
|
||||||
|
void * reallocated_mem =
|
||||||
|
rclcpp::allocator::retyped_reallocate<int, std::allocator<int>>(
|
||||||
|
allocated_mem, 2u, untyped_allocator);
|
||||||
|
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
|
||||||
|
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
|
||||||
|
ASSERT_TRUE(nullptr != reallocated_mem);
|
||||||
|
|
||||||
|
auto code2 = [&untyped_allocator, reallocated_mem]() {
|
||||||
|
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
|
||||||
|
reallocated_mem, untyped_allocator);
|
||||||
|
};
|
||||||
|
EXPECT_NO_THROW(code2());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(TestAllocatorCommon, get_rcl_allocator) {
|
TEST(TestAllocatorCommon, get_rcl_allocator) {
|
||||||
std::allocator<int> allocator;
|
std::allocator<int> allocator;
|
||||||
auto rcl_allocator = rclcpp::allocator::get_rcl_allocator<int>(allocator);
|
auto rcl_allocator = rclcpp::allocator::get_rcl_allocator<int>(allocator);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user