Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04f85067e8 | ||
|
|
70f9ed58d2 | ||
|
|
e2af9da76c | ||
|
|
880d89e583 | ||
|
|
810ff6a8d6 | ||
|
|
7e4e72c70d | ||
|
|
d5d4f6c44c | ||
|
|
19e443bce9 | ||
|
|
4551b69f6e | ||
|
|
785b45a2fc | ||
|
|
c5b427c2ec | ||
|
|
3ce946f6e9 | ||
|
|
ebb6175dfa | ||
|
|
fc13cfe5fe | ||
|
|
331bcb2ec9 | ||
|
|
4db3e3303b | ||
|
|
bda164fb4d | ||
|
|
a35bc62b8c | ||
|
|
8a9f0468e3 | ||
|
|
6a2d90ebf8 | ||
|
|
c21065e979 | ||
|
|
c4ee11a5c7 | ||
|
|
14ecbc3f0b | ||
|
|
8a4cb48b2c | ||
|
|
aa634b28df | ||
|
|
8ec31edd4a | ||
|
|
a709d81a93 | ||
|
|
a35793ad28 | ||
|
|
7cba3c4882 | ||
|
|
27e800b910 | ||
|
|
e6f6b2a7ad | ||
|
|
6c95d10cca | ||
|
|
a5a7febb60 | ||
|
|
7373669455 | ||
|
|
ae930aa2e5 | ||
|
|
24846c3109 | ||
|
|
160da7b432 | ||
|
|
22939ddf9b | ||
|
|
ea1d764f42 | ||
|
|
82666affcd | ||
|
|
0be3acf32f | ||
|
|
34005e903f | ||
|
|
288be9c981 | ||
|
|
93028ff38d |
@@ -2,100 +2,59 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
30.1.5 (2026-02-09)
|
||||
29.5.7 (2026-02-09)
|
||||
-------------------
|
||||
* remove default: so that compiler can detect the missing case. (`#3048 <https://github.com/ros2/rclcpp/issues/3048>`_)
|
||||
* use weak_ptr for rcl entities in the memory strategy. (`#2988 <https://github.com/ros2/rclcpp/issues/2988>`_)
|
||||
* remove test_static_executor_entities_collector.cpp (`#3041 <https://github.com/ros2/rclcpp/issues/3041>`_)
|
||||
* include the 1st spin that might throw the exception. (`#3042 <https://github.com/ros2/rclcpp/issues/3042>`_)
|
||||
* print warning message on owner node if the parameter operation fails. (`#3037 <https://github.com/ros2/rclcpp/issues/3037>`_)
|
||||
* fix context in wait for message wait set (`#3030 <https://github.com/ros2/rclcpp/issues/3030>`_)
|
||||
* Revert "construct wait set with passed in context (`#3021 <https://github.com/ros2/rclcpp/issues/3021>`_)" (`#3028 <https://github.com/ros2/rclcpp/issues/3028>`_)
|
||||
* construct wait set with passed in context (`#3021 <https://github.com/ros2/rclcpp/issues/3021>`_)
|
||||
* Improve the robustness of the TopicEndpointInfo constructor (`#3013 <https://github.com/ros2/rclcpp/issues/3013>`_)
|
||||
* Deprecate the shared_ptr<MessageT> subscription callback signatures (`#2975 <https://github.com/ros2/rclcpp/issues/2975>`_)
|
||||
* Contributors: Barry Xu, Maurice Alexander Purnawan, Michael Carroll, Rahat Dhande, Tomoya Fujita
|
||||
* include the 1st spin that might throw the exception. (`#3042 <https://github.com/ros2/rclcpp/issues/3042>`_) (`#3044 <https://github.com/ros2/rclcpp/issues/3044>`_)
|
||||
* print warning message on owner node if the parameter operation fails. (`#3037 <https://github.com/ros2/rclcpp/issues/3037>`_) (`#3038 <https://github.com/ros2/rclcpp/issues/3038>`_)
|
||||
* remove test_static_executor_entities_collector.cpp (`#3041 <https://github.com/ros2/rclcpp/issues/3041>`_) (`#3045 <https://github.com/ros2/rclcpp/issues/3045>`_)
|
||||
* fix context in wait for message wait set (`#3030 <https://github.com/ros2/rclcpp/issues/3030>`_) (`#3031 <https://github.com/ros2/rclcpp/issues/3031>`_)
|
||||
* Improve the robustness of the TopicEndpointInfo constructor (`#3013 <https://github.com/ros2/rclcpp/issues/3013>`_) (`#3014 <https://github.com/ros2/rclcpp/issues/3014>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
30.1.4 (2025-12-23)
|
||||
29.5.6 (2025-12-23)
|
||||
-------------------
|
||||
* Updated deprecated ament_index_cpp API (`#3011 <https://github.com/ros2/rclcpp/issues/3011>`_)
|
||||
* Unified Node Interfaces: Add const version of get_node_x_interface() (`#3006 <https://github.com/ros2/rclcpp/issues/3006>`_)
|
||||
* Parameter Descriptor Simplification (`#2179 <https://github.com/ros2/rclcpp/issues/2179>`_)
|
||||
* ParameterEventHandler support ContentFiltering (`#2971 <https://github.com/ros2/rclcpp/issues/2971>`_)
|
||||
* update policy_name_from_kind && test_qos (`#2156 <https://github.com/ros2/rclcpp/issues/2156>`_)
|
||||
* Add ability to disable and enable subscription's callbacks (`#2985 <https://github.com/ros2/rclcpp/issues/2985>`_)
|
||||
* Switch to isolated testing via rmw_test_fixture (`#2929 <https://github.com/ros2/rclcpp/issues/2929>`_)
|
||||
* remove I/O from signal handler. (`#2986 <https://github.com/ros2/rclcpp/issues/2986>`_)
|
||||
* Contributors: Alejandro Hernández Cordero, Andrianov Roman, Barry Xu, Lucas Wendland, Michael Orlov, Tomoya Fujita, fabianhirmann, yadunund
|
||||
* Unified Node Interfaces: Add const version of get_node_x_interface() (`#3006 <https://github.com/ros2/rclcpp/issues/3006>`_) (`#3008 <https://github.com/ros2/rclcpp/issues/3008>`_)
|
||||
* remove I/O from signal handler. (`#3000 <https://github.com/ros2/rclcpp/issues/3000>`_)
|
||||
* correct test function descriptions (`#2970 <https://github.com/ros2/rclcpp/issues/2970>`_) (`#2992 <https://github.com/ros2/rclcpp/issues/2992>`_)
|
||||
* Contributors: Tomoya Fujita, mergify[bot]
|
||||
|
||||
30.1.3 (2025-11-18)
|
||||
29.5.5 (2025-11-18)
|
||||
-------------------
|
||||
* correct test function descriptions (`#2970 <https://github.com/ros2/rclcpp/issues/2970>`_)
|
||||
* add : get clients, servers info (`#2569 <https://github.com/ros2/rclcpp/issues/2569>`_)
|
||||
* Fix REP url locations (`#2987 <https://github.com/ros2/rclcpp/issues/2987>`_)
|
||||
* Contributors: Minju, Lee, Tim Clephas, Yuchen966
|
||||
* Fix REP url locations (`#2987 <https://github.com/ros2/rclcpp/issues/2987>`_) (`#2989 <https://github.com/ros2/rclcpp/issues/2989>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
30.1.2 (2025-10-21)
|
||||
29.5.4 (2025-10-21)
|
||||
-------------------
|
||||
* clear handles before node destruction in test_memory_strategy. (`#2969 <https://github.com/ros2/rclcpp/issues/2969>`_)
|
||||
* Added static assert asserting custom types have no overloaded operator new (`#2954 <https://github.com/ros2/rclcpp/issues/2954>`_)
|
||||
* Store graph listener inside the context instead of the node graph (`#2952 <https://github.com/ros2/rclcpp/issues/2952>`_)
|
||||
* Reapply "Catch the exception from rate.sleep() if the context is invalid. (`#2956 <https://github.com/ros2/rclcpp/issues/2956>`_)" (`#2963 <https://github.com/ros2/rclcpp/issues/2963>`_) (`#2964 <https://github.com/ros2/rclcpp/issues/2964>`_)
|
||||
* Revert "Catch the exception from rate.sleep() if the context is invalid. (`#2956 <https://github.com/ros2/rclcpp/issues/2956>`_)" (`#2963 <https://github.com/ros2/rclcpp/issues/2963>`_)
|
||||
* Catch the exception from rate.sleep() if the context is invalid. (`#2956 <https://github.com/ros2/rclcpp/issues/2956>`_)
|
||||
* update Time documentation (`#2955 <https://github.com/ros2/rclcpp/issues/2955>`_)
|
||||
* Contributors: Ilario A. Azzollini, Ivo Ivanov, Skyler Medeiros, Tomoya Fujita
|
||||
|
||||
30.1.1 (2025-09-11)
|
||||
29.5.3 (2025-09-11)
|
||||
-------------------
|
||||
* Removed warning (`#2949 <https://github.com/ros2/rclcpp/issues/2949>`_)
|
||||
* add note about problems with spin_until_future_complete (`#2849 <https://github.com/ros2/rclcpp/issues/2849>`_)
|
||||
* deprecate rclcpp::spin_some and rclcpp::spin_all (`#2848 <https://github.com/ros2/rclcpp/issues/2848>`_)
|
||||
* Improve the function extract_type_identifier (`#2923 <https://github.com/ros2/rclcpp/issues/2923>`_)
|
||||
* Allow for implicitly convertable loggers as well (`#2922 <https://github.com/ros2/rclcpp/issues/2922>`_)
|
||||
* Contributors: Alberto Soragna, Alejandro Hernández Cordero, Barry Xu, Tim Clephas
|
||||
* Fix: improve exception context for parameter_value_from (`#2917 <https://github.com/ros2/rclcpp/issues/2917>`_) (`#2919 <https://github.com/ros2/rclcpp/issues/2919>`_)
|
||||
* Allow for implicitly convertable loggers as well (`#2922 <https://github.com/ros2/rclcpp/issues/2922>`_) (`#2936 <https://github.com/ros2/rclcpp/issues/2936>`_)
|
||||
* Fix `start_type_description_service` param handling (`#2897 <https://github.com/ros2/rclcpp/issues/2897>`_) (`#2908 <https://github.com/ros2/rclcpp/issues/2908>`_)
|
||||
* Add qos parameter for wait_for_message function (`#2903 <https://github.com/ros2/rclcpp/issues/2903>`_) (`#2905 <https://github.com/ros2/rclcpp/issues/2905>`_)
|
||||
* Expose `typesupport_helpers` API needed for the Rosbag2 (`#2858 <https://github.com/ros2/rclcpp/issues/2858>`_) (`#2901 <https://github.com/ros2/rclcpp/issues/2901>`_)
|
||||
* Fujitatomoya/test append parameter override (`#2896 <https://github.com/ros2/rclcpp/issues/2896>`_) (`#2899 <https://github.com/ros2/rclcpp/issues/2899>`_)
|
||||
* Add overload of `append_parameter_override` (`#2891 <https://github.com/ros2/rclcpp/issues/2891>`_) (`#2894 <https://github.com/ros2/rclcpp/issues/2894>`_)
|
||||
* Contributors: Tim Clephas, mergify[bot]
|
||||
|
||||
30.1.0 (2025-07-29)
|
||||
29.5.2 (2025-07-07)
|
||||
-------------------
|
||||
* Fix: improve exception context for parameter_value_from (`#2917 <https://github.com/ros2/rclcpp/issues/2917>`_)
|
||||
* Fix `start_type_description_service` param handling (`#2897 <https://github.com/ros2/rclcpp/issues/2897>`_)
|
||||
* Add qos parameter for wait_for_message function (`#2903 <https://github.com/ros2/rclcpp/issues/2903>`_)
|
||||
* Fujitatomoya/test append parameter override (`#2896 <https://github.com/ros2/rclcpp/issues/2896>`_)
|
||||
* Expose `typesupport_helpers` API needed for the Rosbag2 (`#2858 <https://github.com/ros2/rclcpp/issues/2858>`_)
|
||||
* Remove comment about now-removed StaticSingleThreadedExecutor (`#2893 <https://github.com/ros2/rclcpp/issues/2893>`_)
|
||||
* Add overload of `append_parameter_override` (`#2891 <https://github.com/ros2/rclcpp/issues/2891>`_)
|
||||
* fix: Don't deadlock if removing shutdown callbacks in a shutdown callback (`#2886 <https://github.com/ros2/rclcpp/issues/2886>`_)
|
||||
* Contributors: Christophe Bedard, Janosch Machowinski, Michael Orlov, Michiel Leegwater, Patrick Roncagliolo, Sriharsha Ghanta, Tomoya Fujita
|
||||
* Shutdown deadlock fix jazzy (`#2887 <https://github.com/ros2/rclcpp/issues/2887>`_) (`#2888 <https://github.com/ros2/rclcpp/issues/2888>`_)
|
||||
* Fix test_publisher_with_system_default_qos (`#2881 <https://github.com/ros2/rclcpp/issues/2881>`_) (`#2884 <https://github.com/ros2/rclcpp/issues/2884>`_)
|
||||
* Contributors: Tomoya Fujita, Janosch Machowinski
|
||||
|
||||
30.0.0 (2025-07-01)
|
||||
-------------------
|
||||
* Hand-code logging.hpp (`#2870 <https://github.com/ros2/rclcpp/issues/2870>`_)
|
||||
* Adressed TODO in node_graph (`#2877 <https://github.com/ros2/rclcpp/issues/2877>`_)
|
||||
* fix test_publisher_with_system_default_qos. (`#2881 <https://github.com/ros2/rclcpp/issues/2881>`_)
|
||||
* Contributors: Alejandro Hernández Cordero, Chris Lalancette, Tomoya Fujita
|
||||
|
||||
29.6.1 (2025-06-23)
|
||||
-------------------
|
||||
* Fix for memory leaks in rclcpp::SerializedMessage (`#2861 <https://github.com/ros2/rclcpp/issues/2861>`_)
|
||||
* Removed warning test_qos (`#2859 <https://github.com/ros2/rclcpp/issues/2859>`_)
|
||||
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
|
||||
* get_all_data_impl() does not handle null pointers properly, causing segmentation fault (`#2840 <https://github.com/ros2/rclcpp/issues/2840>`_)
|
||||
* QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (`#2841 <https://github.com/ros2/rclcpp/issues/2841>`_)
|
||||
* remove get_notify_guard_condition from NodeBaseInterface. (`#2839 <https://github.com/ros2/rclcpp/issues/2839>`_)
|
||||
* Removed deprecated StaticSingleThreadedExecutor (`#2835 <https://github.com/ros2/rclcpp/issues/2835>`_)
|
||||
* Removed deprecated rcpputils Path (`#2834 <https://github.com/ros2/rclcpp/issues/2834>`_)
|
||||
* Add range constraints for applicable array parameters (`#2828 <https://github.com/ros2/rclcpp/issues/2828>`_)
|
||||
* Update RingBufferImplementation to clear internal data. (`#2837 <https://github.com/ros2/rclcpp/issues/2837>`_)
|
||||
* Removed deprecated cancel_sleep_or_wait (`#2836 <https://github.com/ros2/rclcpp/issues/2836>`_)
|
||||
* Add missing 's' to 'NodeParametersInterface' in doc/comment (`#2831 <https://github.com/ros2/rclcpp/issues/2831>`_)
|
||||
* subordinate node consistent behavior and update docstring. (`#2822 <https://github.com/ros2/rclcpp/issues/2822>`_)
|
||||
* Contributors: Alejandro Hernández Cordero, Alex Youngs, Christophe Bedard, Michael Carlstrom, Michael Orlov, Tomoya Fujita
|
||||
|
||||
29.6.0 (2025-04-25)
|
||||
29.5.1 (2025-06-23)
|
||||
-------------------
|
||||
* Removed warning test_qos (`#2859 <https://github.com/ros2/rclcpp/issues/2859>`_) (`#2873 <https://github.com/ros2/rclcpp/issues/2873>`_)
|
||||
* Fix for memory leaks in rclcpp::SerializedMessage (`#2861 <https://github.com/ros2/rclcpp/issues/2861>`_) (`#2863 <https://github.com/ros2/rclcpp/issues/2863>`_)
|
||||
* get_all_data_impl() does not handle null pointers properly, causing segmentation fault (backport `#2840 <https://github.com/ros2/rclcpp/issues/2840>`_) (`#2850 <https://github.com/ros2/rclcpp/issues/2850>`_)
|
||||
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
|
||||
* QoSInitialization::from_rmw does not validate invalid history policy values, leading to silent failures (`#2841 <https://github.com/ros2/rclcpp/issues/2841>`_) (`#2846 <https://github.com/ros2/rclcpp/issues/2846>`_)
|
||||
* Add missing 's' to 'NodeParametersInterface' in doc/comment (`#2831 <https://github.com/ros2/rclcpp/issues/2831>`_) (`#2833 <https://github.com/ros2/rclcpp/issues/2833>`_)
|
||||
* subordinate node consistent behavior and update docstring. (`#2822 <https://github.com/ros2/rclcpp/issues/2822>`_) (`#2830 <https://github.com/ros2/rclcpp/issues/2830>`_)
|
||||
* throws std::invalid_argument if ParameterEvent is NULL. (`#2814 <https://github.com/ros2/rclcpp/issues/2814>`_)
|
||||
* Removed clang warnings (`#2823 <https://github.com/ros2/rclcpp/issues/2823>`_)
|
||||
* Contributors: Alejandro Hernández Cordero, Tomoya Fujita
|
||||
* Contributors: Alejandro Hernández Cordero, Tomoya Fujita, mergify[bot]
|
||||
|
||||
29.5.0 (2025-04-18)
|
||||
-------------------
|
||||
|
||||
@@ -70,6 +70,7 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/executors/executor_notify_waitable.cpp
|
||||
src/rclcpp/executors/multi_threaded_executor.cpp
|
||||
src/rclcpp/executors/single_threaded_executor.cpp
|
||||
src/rclcpp/executors/static_single_threaded_executor.cpp
|
||||
src/rclcpp/expand_topic_or_service_name.cpp
|
||||
src/rclcpp/experimental/executors/events_executor/events_executor.cpp
|
||||
src/rclcpp/experimental/timers_manager.cpp
|
||||
@@ -103,7 +104,6 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/node_options.cpp
|
||||
src/rclcpp/parameter.cpp
|
||||
src/rclcpp/parameter_client.cpp
|
||||
src/rclcpp/parameter_descriptor_wrapper.cpp
|
||||
src/rclcpp/parameter_event_handler.cpp
|
||||
src/rclcpp/parameter_events_filter.cpp
|
||||
src/rclcpp/parameter_map.cpp
|
||||
@@ -147,6 +147,27 @@ set(Python3_FIND_UNVERSIONED_NAMES FIRST)
|
||||
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
# "watch" template for changes
|
||||
configure_file(
|
||||
"resource/logging.hpp.em"
|
||||
"logging.hpp.em.watch"
|
||||
COPYONLY
|
||||
)
|
||||
# generate header with logging macros
|
||||
set(python_code_logging
|
||||
"import em"
|
||||
"em.invoke(['-o', 'include/rclcpp/logging.hpp', '${CMAKE_CURRENT_SOURCE_DIR}/resource/logging.hpp.em'])")
|
||||
string(REPLACE ";" "$<SEMICOLON>" python_code_logging "${python_code_logging}")
|
||||
add_custom_command(OUTPUT include/rclcpp/logging.hpp
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp"
|
||||
COMMAND Python3::Interpreter ARGS -c "${python_code_logging}"
|
||||
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/logging.hpp.em.watch"
|
||||
COMMENT "Expanding logging.hpp.em"
|
||||
VERBATIM
|
||||
)
|
||||
list(APPEND ${PROJECT_NAME}_SRCS
|
||||
include/rclcpp/logging.hpp)
|
||||
|
||||
file(GLOB interface_files "include/rclcpp/node_interfaces/node_*_interface.hpp")
|
||||
foreach(interface_file ${interface_files})
|
||||
get_filename_component(interface_name ${interface_file} NAME_WE)
|
||||
|
||||
@@ -21,22 +21,6 @@ GENERATE_LATEX = NO
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
EXCLUDE_SYMBOLS += RCLCPP_STATIC_ASSERT_LOGGER
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_ONCE
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_EXPRESSION
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_FUNCTION
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_SKIPFIRST
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_TIME_POINT_FUNC
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_THROTTLE
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_SKIPFIRST_THROTTLE
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_ONCE
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_EXPRESSION
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_FUNCTION
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_SKIPFIRST
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_THROTTLE
|
||||
EXCLUDE_SYMBOLS += RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
|
||||
PREDEFINED += DOXYGEN_ONLY
|
||||
PREDEFINED += RCLCPP_LOCAL=
|
||||
PREDEFINED += RCLCPP_PUBLIC=
|
||||
|
||||
@@ -15,10 +15,8 @@
|
||||
#ifndef RCLCPP__ANY_SUBSCRIPTION_CALLBACK_HPP_
|
||||
#define RCLCPP__ANY_SUBSCRIPTION_CALLBACK_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -377,19 +375,7 @@ public:
|
||||
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
||||
}
|
||||
|
||||
AnySubscriptionCallback(const AnySubscriptionCallback & other)
|
||||
: callback_variant_(other.callback_variant_),
|
||||
callback_disabled_(other.callback_disabled_.load()),
|
||||
subscribed_type_allocator_(other.subscribed_type_allocator_),
|
||||
subscribed_type_deleter_(other.subscribed_type_deleter_),
|
||||
ros_message_type_allocator_(other.ros_message_type_allocator_),
|
||||
ros_message_type_deleter_(other.ros_message_type_deleter_),
|
||||
serialized_message_allocator_(other.serialized_message_allocator_),
|
||||
serialized_message_deleter_(other.serialized_message_deleter_)
|
||||
{
|
||||
allocator::set_allocator_for_deleter(&subscribed_type_deleter_, &subscribed_type_allocator_);
|
||||
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
||||
}
|
||||
AnySubscriptionCallback(const AnySubscriptionCallback &) = default;
|
||||
|
||||
/// Generic function for setting the callback.
|
||||
/**
|
||||
@@ -407,91 +393,12 @@ public:
|
||||
// converted to one another, e.g. shared_ptr and unique_ptr.
|
||||
using scbth = detail::SubscriptionCallbackTypeHelper<MessageT, CallbackT>;
|
||||
|
||||
// Determine if the given CallbackT is a deprecated signature or not.
|
||||
constexpr auto is_deprecated =
|
||||
rclcpp::function_traits::same_arguments<
|
||||
typename scbth::callback_type,
|
||||
std::function<void(std::shared_ptr<SubscribedType>)>
|
||||
>::value ||
|
||||
rclcpp::function_traits::same_arguments<
|
||||
typename scbth::callback_type,
|
||||
std::function<void(std::shared_ptr<SubscribedType>, const rclcpp::MessageInfo &)>
|
||||
>::value ||
|
||||
rclcpp::function_traits::same_arguments<
|
||||
typename scbth::callback_type,
|
||||
std::function<void(std::shared_ptr<ROSMessageType>)>
|
||||
>::value ||
|
||||
rclcpp::function_traits::same_arguments<
|
||||
typename scbth::callback_type,
|
||||
std::function<void(std::shared_ptr<ROSMessageType>, const rclcpp::MessageInfo &)>
|
||||
>::value ||
|
||||
rclcpp::function_traits::same_arguments<
|
||||
typename scbth::callback_type,
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)>
|
||||
>::value ||
|
||||
rclcpp::function_traits::same_arguments<
|
||||
typename scbth::callback_type,
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>, const rclcpp::MessageInfo &)>
|
||||
>::value;
|
||||
|
||||
// Use the discovered type to force the type of callback when assigning
|
||||
// into the variant.
|
||||
if constexpr (is_deprecated) {
|
||||
// If deprecated, call sub-routine that is deprecated.
|
||||
set_deprecated(static_cast<typename scbth::callback_type>(callback));
|
||||
} else {
|
||||
// Otherwise just assign it.
|
||||
callback_variant_ = static_cast<typename scbth::callback_type>(callback);
|
||||
}
|
||||
callback_variant_ = static_cast<typename scbth::callback_type>(callback);
|
||||
|
||||
// Return copy of self for easier testing, normally will be compiled out.
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Function for shared_ptr to non-const MessageT, which is deprecated.
|
||||
template<typename SetT>
|
||||
// *INDENT-OFF*
|
||||
#if !defined(RCLCPP_AVOID_DEPRECATIONS_FOR_UNIT_TESTS)
|
||||
// suppress deprecation warnings in `test_any_subscription_callback.cpp`
|
||||
[[deprecated("use 'void(std::shared_ptr<const MessageT>)' instead")]]
|
||||
#endif
|
||||
// *INDENT-ON*
|
||||
void
|
||||
set_deprecated(std::function<void(std::shared_ptr<SetT>)> callback)
|
||||
{
|
||||
callback_variant_ = callback;
|
||||
}
|
||||
|
||||
/// Function for shared_ptr to non-const MessageT with MessageInfo, which is deprecated.
|
||||
template<typename SetT>
|
||||
// *INDENT-OFF*
|
||||
#if !defined(RCLCPP_AVOID_DEPRECATIONS_FOR_UNIT_TESTS)
|
||||
// suppress deprecation warnings in `test_any_subscription_callback.cpp`
|
||||
[[deprecated(
|
||||
"use 'void(std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)' instead"
|
||||
)]]
|
||||
#endif
|
||||
// *INDENT-ON*
|
||||
void
|
||||
set_deprecated(std::function<void(std::shared_ptr<SetT>, const rclcpp::MessageInfo &)> callback)
|
||||
{
|
||||
callback_variant_ = callback;
|
||||
}
|
||||
|
||||
/// Disable the callback from being called during dispatch.
|
||||
void disable()
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
|
||||
callback_disabled_.store(true);
|
||||
}
|
||||
|
||||
/// Enable the callback to be called during dispatch.
|
||||
void enable()
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
|
||||
callback_disabled_.store(false);
|
||||
}
|
||||
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
|
||||
create_ros_unique_ptr_from_ros_shared_ptr_message(
|
||||
const std::shared_ptr<const ROSMessageType> & message)
|
||||
@@ -562,10 +469,6 @@ public:
|
||||
std::shared_ptr<ROSMessageType> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
|
||||
if (callback_disabled_.load()) {
|
||||
return;
|
||||
}
|
||||
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
@@ -666,10 +569,6 @@ public:
|
||||
std::shared_ptr<const rclcpp::SerializedMessage> serialized_message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
|
||||
if (callback_disabled_.load()) {
|
||||
return;
|
||||
}
|
||||
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
@@ -749,10 +648,6 @@ public:
|
||||
std::shared_ptr<const SubscribedType> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
|
||||
if (callback_disabled_.load()) {
|
||||
return;
|
||||
}
|
||||
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), true);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
@@ -883,10 +778,6 @@ public:
|
||||
std::unique_ptr<SubscribedType, SubscribedTypeDeleter> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> callback_lock(callback_mutex_);
|
||||
if (callback_disabled_.load()) {
|
||||
return;
|
||||
}
|
||||
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), true);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
@@ -1081,8 +972,6 @@ private:
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2162r0.html
|
||||
// For now, compose the variant into this class as a private attribute.
|
||||
typename HelperT::variant_type callback_variant_;
|
||||
std::recursive_mutex callback_mutex_;
|
||||
std::atomic_bool callback_disabled_{false};
|
||||
|
||||
SubscribedTypeAllocator subscribed_type_allocator_;
|
||||
SubscribedTypeDeleter subscribed_type_deleter_;
|
||||
|
||||
@@ -200,6 +200,21 @@ public:
|
||||
bool
|
||||
ros_time_is_active();
|
||||
|
||||
/**
|
||||
* Deprecated. This API is broken, as there is no way to get a deep
|
||||
* copy of a clock. Therefore one can experience spurious wakeups triggered
|
||||
* by some other instance of a clock.
|
||||
*
|
||||
* Cancels an ongoing or future sleep operation of one thread.
|
||||
*
|
||||
* This function can be used by one thread, to wakeup another thread that is
|
||||
* blocked using any of the sleep_ or wait_ methods of this class.
|
||||
*/
|
||||
[[deprecated("Use ClockConditionalVariable")]]
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
cancel_sleep_or_wait();
|
||||
|
||||
/// Return the rcl_clock_t clock handle
|
||||
RCLCPP_PUBLIC
|
||||
rcl_clock_t *
|
||||
|
||||
@@ -37,10 +37,6 @@
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace graph_listener
|
||||
{
|
||||
class GraphListener;
|
||||
} // namespace graph_listener
|
||||
|
||||
/// Thrown when init is called on an already initialized context.
|
||||
class ContextAlreadyInitialized : public std::runtime_error
|
||||
@@ -313,10 +309,6 @@ public:
|
||||
std::shared_ptr<rcl_context_t>
|
||||
get_rcl_context();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<rclcpp::graph_listener::GraphListener>
|
||||
get_graph_listener();
|
||||
|
||||
/// Sleep for a given period of time or until shutdown() is called.
|
||||
/**
|
||||
* This function can be interrupted early if:
|
||||
@@ -389,19 +381,16 @@ private:
|
||||
std::recursive_mutex sub_contexts_mutex_;
|
||||
|
||||
std::vector<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
|
||||
mutable std::recursive_mutex on_shutdown_callbacks_mutex_;
|
||||
mutable std::mutex on_shutdown_callbacks_mutex_;
|
||||
|
||||
std::vector<std::shared_ptr<PreShutdownCallback>> pre_shutdown_callbacks_;
|
||||
mutable std::recursive_mutex pre_shutdown_callbacks_mutex_;
|
||||
mutable std::mutex pre_shutdown_callbacks_mutex_;
|
||||
|
||||
/// Condition variable for timed sleep (see sleep_for).
|
||||
std::condition_variable interrupt_condition_variable_;
|
||||
/// Mutex for protecting the global condition variable.
|
||||
std::mutex interrupt_mutex_;
|
||||
|
||||
/// Graph Listener which waits on graph changes for the node and is shared across nodes.
|
||||
std::shared_ptr<rclcpp::graph_listener::GraphListener> graph_listener_;
|
||||
|
||||
/// Keep shared ownership of global vector of weak contexts
|
||||
std::shared_ptr<WeakContextsWrapper> weak_contexts_;
|
||||
|
||||
|
||||
@@ -270,8 +270,8 @@ apply_qos_override(
|
||||
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
|
||||
reliability, RELIABILITY, value, qos);
|
||||
break;
|
||||
case QosPolicyKind::Invalid:
|
||||
throw std::invalid_argument{"invalid QosPolicyKind"};
|
||||
default:
|
||||
throw std::invalid_argument{"unknown QosPolicyKind"};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,11 +332,9 @@ get_default_qos_param_value(rclcpp::QosPolicyKind kind, const rclcpp::QoS & qos)
|
||||
return ParameterValue(
|
||||
check_if_stringified_policy_is_null(
|
||||
rmw_qos_reliability_policy_to_str(rmw_qos.reliability), kind));
|
||||
case QosPolicyKind::Invalid:
|
||||
throw std::invalid_argument{"invalid QoS policy kind"};
|
||||
default:
|
||||
throw std::invalid_argument{"unknown QoS policy kind"};
|
||||
}
|
||||
|
||||
return ParameterValue();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -29,7 +29,7 @@ template<typename OptionsT, typename NodeBaseT>
|
||||
bool
|
||||
resolve_enable_topic_statistics(const OptionsT & options, const NodeBaseT & node_base)
|
||||
{
|
||||
bool topic_stats_enabled = false;
|
||||
bool topic_stats_enabled;
|
||||
switch (options.topic_stats_options.state) {
|
||||
case TopicStatisticsState::Enable:
|
||||
topic_stats_enabled = true;
|
||||
|
||||
@@ -30,7 +30,7 @@ template<typename OptionsT, typename NodeBaseT>
|
||||
bool
|
||||
resolve_use_intra_process(const OptionsT & options, const NodeBaseT & node_base)
|
||||
{
|
||||
bool use_intra_process = false;
|
||||
bool use_intra_process;
|
||||
switch (options.use_intra_process_comm) {
|
||||
case IntraProcessSetting::Enable:
|
||||
use_intra_process = true;
|
||||
@@ -43,6 +43,7 @@ resolve_use_intra_process(const OptionsT & options, const NodeBaseT & node_base)
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unrecognized IntraProcessSetting value");
|
||||
break;
|
||||
}
|
||||
|
||||
return use_intra_process;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#ifndef RCLCPP__EVENT_HANDLER_HPP_
|
||||
#define RCLCPP__EVENT_HANDLER_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -111,14 +110,6 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~EventHandlerBase();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void enable() = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void disable() = 0;
|
||||
|
||||
/// Get the number of ready events
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
@@ -201,7 +192,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_event_callback_mutex_);
|
||||
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
|
||||
@@ -224,7 +215,7 @@ public:
|
||||
void
|
||||
clear_on_ready_callback() override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_event_callback_mutex_);
|
||||
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;
|
||||
@@ -243,7 +234,7 @@ protected:
|
||||
void
|
||||
set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
|
||||
|
||||
std::recursive_mutex on_new_event_callback_mutex_;
|
||||
std::recursive_mutex callback_mutex_;
|
||||
std::function<void(size_t)> on_new_event_callback_{nullptr};
|
||||
|
||||
rcl_event_t event_handle_;
|
||||
@@ -311,10 +302,6 @@ public:
|
||||
void
|
||||
execute(const std::shared_ptr<void> & data) override
|
||||
{
|
||||
std::unique_lock<std::mutex> event_callback_lock(event_callback_mutex_);
|
||||
if (disabled_.load()) {
|
||||
return;
|
||||
}
|
||||
if (!data) {
|
||||
throw std::runtime_error("'data' is empty");
|
||||
}
|
||||
@@ -323,53 +310,12 @@ public:
|
||||
callback_ptr.reset();
|
||||
}
|
||||
|
||||
/// Disable the event callback from being called when execute(..) invoked
|
||||
/**
|
||||
* This will also temporarily remove the on_new_event_callback from the underlying rmw layer,
|
||||
* so that it is not called from the middleware while disabled.
|
||||
*/
|
||||
void disable() override
|
||||
{
|
||||
{
|
||||
// Temporary remove the on_new_event_callback_ to prevent it from being called
|
||||
std::lock_guard<std::recursive_mutex> on_new_event_lock(on_new_event_callback_mutex_);
|
||||
if (on_new_event_callback_) {
|
||||
set_on_new_event_callback(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
std::lock_guard<std::mutex> event_callback_lock(event_callback_mutex_);
|
||||
disabled_.store(true);
|
||||
}
|
||||
|
||||
/// Enable the event callback to be called when execute(..) invoked
|
||||
/**
|
||||
* This will also set back the on_new_event_callback to the underlying rmw layer, if it was
|
||||
* previously removed with disable().
|
||||
*/
|
||||
void enable() override
|
||||
{
|
||||
{
|
||||
// Set callback again if it was previously removed in disable()
|
||||
std::lock_guard<std::recursive_mutex> on_new_event_lock(on_new_event_callback_mutex_);
|
||||
if (on_new_event_callback_) {
|
||||
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_));
|
||||
}
|
||||
}
|
||||
std::lock_guard<std::mutex> event_callback_lock(event_callback_mutex_);
|
||||
disabled_.store(false);
|
||||
}
|
||||
|
||||
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_;
|
||||
std::mutex event_callback_mutex_;
|
||||
std::atomic_bool disabled_{false};
|
||||
};
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
@@ -371,9 +371,6 @@ public:
|
||||
* If the time spent inside the blocking loop exceeds this timeout, return a TIMEOUT return
|
||||
* code.
|
||||
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
|
||||
* \note This method will check the future and the timeout only when the executor is woken up.
|
||||
* If this future is unrelated to an executor's entity, this method will not correctly detect
|
||||
* when it's completed and therefore may wait forever and never time out.
|
||||
*/
|
||||
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
|
||||
FutureReturnCode
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "rclcpp/executors/multi_threaded_executor.hpp"
|
||||
#include "rclcpp/executors/single_threaded_executor.hpp"
|
||||
#include "rclcpp/executors/static_single_threaded_executor.hpp"
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
@@ -28,82 +29,24 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Create a default single-threaded executor and execute all available work exhaustively.
|
||||
* @param node_ptr Shared pointer to the base interface of the node to spin.
|
||||
* @param max_duration max duration to spin
|
||||
*
|
||||
* This method is deprecated because it can lead to very bad performance if used in a loop:
|
||||
* each call will create a new executor and register the node, which is an expensive operation.
|
||||
* It's recommended to always manually instantiate an executor and call the methods with
|
||||
* the same name on it.
|
||||
* For example:
|
||||
* SingleThreadedExecutor executor;
|
||||
* executor.add_node(node_ptr);
|
||||
* executor.spin_all(max_duration);
|
||||
* If you are using a non-default context, this should be passed to the executor's constructor.
|
||||
*/
|
||||
[[deprecated("use SingleThreadedExecutor::spin_all instead")]]
|
||||
/// Create a default single-threaded executor and execute all available work exhaustively.
|
||||
/** \param[in] node_ptr Shared pointer to the node to spin. */
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_all(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
std::chrono::nanoseconds max_duration);
|
||||
|
||||
/**
|
||||
* @brief Create a default single-threaded executor and execute all available work exhaustively.
|
||||
* @param node_ptr Shared pointer to the node to spin.
|
||||
* @param max_duration max duration to spin
|
||||
*
|
||||
* This method is deprecated because it can lead to very bad performance if used in a loop:
|
||||
* each call will create a new executor and register the node, which is an expensive operation.
|
||||
* It's recommended to always manually instantiate an executor and call the methods with
|
||||
* the same name on it.
|
||||
* For example:
|
||||
* SingleThreadedExecutor executor;
|
||||
* executor.add_node(node_ptr);
|
||||
* executor.spin_all(max_duration);
|
||||
* If you are using a non-default context, this should be passed to the executor's constructor.
|
||||
*/
|
||||
[[deprecated("use SingleThreadedExecutor::spin_all instead")]]
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration);
|
||||
|
||||
/**
|
||||
* @brief Create a default single-threaded executor and execute any immediately available work.
|
||||
* @param node_ptr Shared pointer to the base interface of the node to spin.
|
||||
*
|
||||
* This method is deprecated because it can lead to very bad performance if used in a loop:
|
||||
* each call will create a new executor and register the node, which is an expensive operation.
|
||||
* It's recommended to always manually instantiate an executor and call the methods with
|
||||
* the same name on it.
|
||||
* For example:
|
||||
* SingleThreadedExecutor executor;
|
||||
* executor.add_node(node_ptr);
|
||||
* executor.spin_some();
|
||||
* If you are using a non-default context, this should be passed to the executor's constructor.
|
||||
*/
|
||||
[[deprecated("use SingleThreadedExecutor::spin_some instead")]]
|
||||
/// Create a default single-threaded executor and execute any immediately available work.
|
||||
/** \param[in] node_ptr Shared pointer to the node to spin. */
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
|
||||
|
||||
/**
|
||||
* @brief Create a default single-threaded executor and execute any immediately available work.
|
||||
* @param node_ptr Shared pointer to the node to spin.
|
||||
*
|
||||
* This method is deprecated because it can lead to very bad performance if used in a loop:
|
||||
* each call will create a new executor and register the node, which is an expensive operation.
|
||||
* It's recommended to always manually instantiate an executor and call the methods with
|
||||
* the same name on it.
|
||||
* For example:
|
||||
* SingleThreadedExecutor executor;
|
||||
* executor.add_node(node_ptr);
|
||||
* executor.spin_some();
|
||||
* If you are using a non-default context, this should be passed to the executor's constructor.
|
||||
*/
|
||||
[[deprecated("use SingleThreadedExecutor::spin_some instead")]]
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some(rclcpp::Node::SharedPtr node_ptr);
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
// Copyright 2019 Nobleo Technology
|
||||
//
|
||||
// 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__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
|
||||
#define RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/executor.hpp"
|
||||
#include "rclcpp/executors/executor_entities_collection.hpp"
|
||||
#include "rclcpp/executors/single_threaded_executor.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
/// Static executor implementation
|
||||
/**
|
||||
* This executor is a static version of the original single threaded executor.
|
||||
* It contains some performance optimization to avoid unnecessary reconstructions of
|
||||
* the executable list for every iteration.
|
||||
* All nodes, callbackgroups, timers, subscriptions etc. are created before
|
||||
* spin() is called, and modified only when an entity is added/removed to/from a node.
|
||||
* This executor is deprecated because these performance improvements have now been
|
||||
* applied to all other executors.
|
||||
* This executor is also considered unstable due to known bugs.
|
||||
* See the unit-tests that are only applied to `StandardExecutors` for information
|
||||
* on the known limitations.
|
||||
*
|
||||
* To run this executor instead of SingleThreadedExecutor replace:
|
||||
* rclcpp::executors::SingleThreadedExecutor exec;
|
||||
* by
|
||||
* rclcpp::executors::StaticSingleThreadedExecutor exec;
|
||||
* in your source code and spin node(s) in the following way:
|
||||
* exec.add_node(node);
|
||||
* exec.spin();
|
||||
* exec.remove_node(node);
|
||||
*/
|
||||
class [[deprecated("Use rclcpp::executors::SingleThreadedExecutor")]] StaticSingleThreadedExecutor
|
||||
: public rclcpp::Executor
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(StaticSingleThreadedExecutor)
|
||||
|
||||
/// Default constructor. See the default constructor for Executor.
|
||||
RCLCPP_PUBLIC
|
||||
explicit StaticSingleThreadedExecutor(
|
||||
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
|
||||
|
||||
/// Default destructor.
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~StaticSingleThreadedExecutor();
|
||||
|
||||
/// Static executor implementation of spin.
|
||||
/**
|
||||
* This function will block until work comes in, execute it, and keep blocking.
|
||||
* It will only be interrupted by a CTRL-C (managed by the global signal handler).
|
||||
* \throws std::runtime_error when spin() called while already spinning
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin() override;
|
||||
|
||||
/// Static executor implementation of spin some
|
||||
/**
|
||||
* This non-blocking function will execute entities that
|
||||
* were ready when this API was called, until timeout or no
|
||||
* more work available. Entities that got ready while
|
||||
* executing work, won't be taken into account here.
|
||||
*
|
||||
* Example:
|
||||
* while(condition) {
|
||||
* spin_some();
|
||||
* sleep(); // User should have some sync work or
|
||||
* // sleep to avoid a 100% CPU usage
|
||||
* }
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0)) override;
|
||||
|
||||
/// Static executor implementation of spin all
|
||||
/**
|
||||
* This non-blocking function will execute entities until timeout (must be >= 0)
|
||||
* or no more work available.
|
||||
* If timeout is `0`, potentially it blocks forever until no more work is available.
|
||||
* If new entities get ready while executing work available, they will be executed
|
||||
* as long as the timeout hasn't expired.
|
||||
*
|
||||
* Example:
|
||||
* while(condition) {
|
||||
* spin_all();
|
||||
* sleep(); // User should have some sync work or
|
||||
* // sleep to avoid a 100% CPU usage
|
||||
* }
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_all(std::chrono::nanoseconds max_duration) override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Executes ready executables from wait set.
|
||||
* @param collection entities to evaluate for ready executables.
|
||||
* @param wait_result result to check for ready executables.
|
||||
* @param spin_once if true executes only the first ready executable.
|
||||
* @return true if any executable was ready.
|
||||
*/
|
||||
bool
|
||||
execute_ready_executables(
|
||||
const rclcpp::executors::ExecutorEntitiesCollection & collection,
|
||||
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result,
|
||||
bool spin_once);
|
||||
|
||||
void
|
||||
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
|
||||
|
||||
void
|
||||
spin_once_impl(std::chrono::nanoseconds timeout) override;
|
||||
|
||||
std::optional<rclcpp::WaitResult<rclcpp::WaitSet>>
|
||||
collect_and_wait(std::chrono::nanoseconds timeout);
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(StaticSingleThreadedExecutor)
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
|
||||
@@ -178,8 +178,6 @@ public:
|
||||
void clear() override
|
||||
{
|
||||
TRACETOOLS_TRACEPOINT(rclcpp_ring_buffer_clear, static_cast<const void *>(this));
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
clear_();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -229,14 +227,6 @@ private:
|
||||
return capacity_ - size_;
|
||||
}
|
||||
|
||||
inline void clear_()
|
||||
{
|
||||
ring_buffer_.clear();
|
||||
size_ = 0;
|
||||
read_index_ = 0;
|
||||
write_index_ = capacity_ - 1;
|
||||
}
|
||||
|
||||
/// Traits for checking if a type is std::unique_ptr
|
||||
template<typename ...>
|
||||
struct is_std_unique_ptr final : std::false_type {};
|
||||
@@ -306,7 +296,7 @@ private:
|
||||
return {};
|
||||
}
|
||||
|
||||
const size_t capacity_;
|
||||
size_t capacity_;
|
||||
|
||||
std::vector<BufferT> ring_buffer_;
|
||||
|
||||
|
||||
@@ -82,9 +82,10 @@ create_intra_process_buffer(
|
||||
|
||||
break;
|
||||
}
|
||||
case IntraProcessBufferType::CallbackDefault:
|
||||
default:
|
||||
{
|
||||
throw std::runtime_error("IntraProcessBufferType::CallbackDefault is not allowed");
|
||||
throw std::runtime_error("Unrecognized IntraProcessBufferType value");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,17 +64,17 @@ public:
|
||||
|
||||
/// Default constructor. See the default constructor for Executor.
|
||||
/**
|
||||
* \param[in] options Options used to configure the executor.
|
||||
* \param[in] events_queue The queue used to store events.
|
||||
* \param[in] execute_timers_separate_thread If true, timers are executed in a separate
|
||||
* thread. If false, timers are executed in the same thread as all other entities.
|
||||
* \param[in] options Options used to configure the executor.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
EventsExecutor(
|
||||
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions(),
|
||||
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue = std::make_unique<
|
||||
rclcpp::experimental::executors::SimpleEventsQueue>(),
|
||||
bool execute_timers_separate_thread = false);
|
||||
bool execute_timers_separate_thread = false,
|
||||
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
|
||||
|
||||
/// Default destructor.
|
||||
RCLCPP_PUBLIC
|
||||
|
||||
@@ -154,29 +154,6 @@ public:
|
||||
execute_impl<SubscribedType>(data);
|
||||
}
|
||||
|
||||
/// Disable callbacks from being called
|
||||
/**
|
||||
* This method will block, until any subscription's callbacks currently being executed are
|
||||
* finished.
|
||||
* This method is thread safe, and provides a safe way to atomically disable the callbacks.
|
||||
*/
|
||||
void disable_callbacks() override
|
||||
{
|
||||
SubscriptionIntraProcessBase::disable_callbacks();
|
||||
any_callback_.disable();
|
||||
}
|
||||
|
||||
/// Enable the callbacks to be called
|
||||
/**
|
||||
* This method is thread safe, and provides a safe way to atomically enable the callbacks
|
||||
* in a multithreaded environment.
|
||||
*/
|
||||
void enable_callbacks() override
|
||||
{
|
||||
SubscriptionIntraProcessBase::enable_callbacks();
|
||||
any_callback_.enable();
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_same<T, rcl_serialized_message_t>::value, void>::type
|
||||
|
||||
@@ -87,22 +87,6 @@ public:
|
||||
void
|
||||
execute(const std::shared_ptr<void> & data) override = 0;
|
||||
|
||||
/// Disable callbacks from being called
|
||||
/**
|
||||
* This function temporary disable on_new_message_callback to prevent it from being called.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void disable_callbacks();
|
||||
|
||||
/// Enable the callbacks to be called
|
||||
/**
|
||||
* This function enable the on_new_message_callback if it was previously set.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void enable_callbacks();
|
||||
|
||||
virtual
|
||||
bool
|
||||
use_take_shared_method() const = 0;
|
||||
@@ -174,7 +158,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
on_new_message_callback_ = new_callback;
|
||||
|
||||
if (unread_count_ > 0) {
|
||||
@@ -192,7 +176,7 @@ public:
|
||||
void
|
||||
clear_on_ready_callback() override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
on_new_message_callback_ = nullptr;
|
||||
}
|
||||
|
||||
@@ -204,9 +188,8 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
std::recursive_mutex on_new_message_callback_mutex_;
|
||||
std::recursive_mutex callback_mutex_;
|
||||
std::function<void(size_t)> on_new_message_callback_ {nullptr};
|
||||
bool on_new_message_callback_disabled_{false};
|
||||
size_t unread_count_{0};
|
||||
rclcpp::GuardCondition gc_;
|
||||
|
||||
@@ -216,13 +199,11 @@ protected:
|
||||
void
|
||||
invoke_on_new_message()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(this->on_new_message_callback_mutex_);
|
||||
if (!on_new_message_callback_disabled_) {
|
||||
if (this->on_new_message_callback_) {
|
||||
this->on_new_message_callback_(1);
|
||||
} else {
|
||||
this->unread_count_++;
|
||||
}
|
||||
std::lock_guard<std::recursive_mutex> lock(this->callback_mutex_);
|
||||
if (this->on_new_message_callback_) {
|
||||
this->on_new_message_callback_(1);
|
||||
} else {
|
||||
this->unread_count_++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,26 +111,6 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<rclcpp::SerializedMessage> create_serialized_message() override;
|
||||
|
||||
/// Disable callbacks from being called
|
||||
/**
|
||||
* This method will block, until any subscription's callbacks provided during construction
|
||||
* currently being executed are finished.
|
||||
* \note This method also temporary removes the on new message callback and all
|
||||
* on new event callbacks from the rmw layer to prevent them from being called. However, this
|
||||
* method will not block and wait until the currently executing on_new_[message]event callbacks
|
||||
* are finished.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void disable_callbacks() override;
|
||||
|
||||
/// Enable the callbacks to be called
|
||||
/**
|
||||
* This method is thread safe, and provides a safe way to atomically enable the callbacks
|
||||
* in a multithreaded environment.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void enable_callbacks() override;
|
||||
|
||||
/// Cast the message to a rclcpp::SerializedMessage and call the callback.
|
||||
RCLCPP_PUBLIC
|
||||
void handle_message(
|
||||
|
||||
@@ -154,12 +154,6 @@ public:
|
||||
bool
|
||||
is_shutdown();
|
||||
|
||||
/// Return true if the graph listener was started.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
is_started();
|
||||
|
||||
protected:
|
||||
/// Main function for the listening thread.
|
||||
RCLCPP_PUBLIC
|
||||
@@ -187,6 +181,7 @@ private:
|
||||
void
|
||||
__shutdown();
|
||||
|
||||
std::weak_ptr<rclcpp::Context> weak_parent_context_;
|
||||
std::shared_ptr<rcl_context_t> rcl_parent_context_;
|
||||
|
||||
std::thread listener_thread_;
|
||||
|
||||
@@ -78,6 +78,34 @@ RCLCPP_PUBLIC
|
||||
Logger
|
||||
get_node_logger(const rcl_node_t * node);
|
||||
|
||||
// TODO(ahcorde): Remove deprecated class on the next release (in Rolling after Kilted).
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
/// Get the current logging directory.
|
||||
/**
|
||||
* For more details of how the logging directory is determined,
|
||||
* see rcl_logging_get_logging_directory().
|
||||
*
|
||||
* \returns the logging directory being used.
|
||||
* \throws rclcpp::exceptions::RCLError if an unexpected error occurs.
|
||||
*/
|
||||
[[deprecated("use rclcpp::get_log_directory instead of rclcpp::get_logging_directory")]]
|
||||
RCLCPP_PUBLIC
|
||||
rcpputils::fs::path
|
||||
get_logging_directory();
|
||||
|
||||
// remove warning suppression
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/// Get the current logging directory.
|
||||
/**
|
||||
* For more details of how the logging directory is determined,
|
||||
|
||||
@@ -1,983 +0,0 @@
|
||||
// Copyright 2017 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__LOGGING_HPP_
|
||||
#define RCLCPP__LOGGING_HPP_
|
||||
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rcutils/logging_macros.h"
|
||||
|
||||
// These are used for compiling out logging macros lower than a minimum severity.
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_DEBUG 0
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_INFO 1
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_WARN 2
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_ERROR 3
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_FATAL 4
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_NONE 5
|
||||
|
||||
#define RCLCPP_STATIC_ASSERT_LOGGER(logger) \
|
||||
do { \
|
||||
static_assert( \
|
||||
::std::is_convertible_v<decltype(logger), ::rclcpp::Logger>, \
|
||||
"First argument to logging macros must be an rclcpp::Logger"); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG
|
||||
* Log a message with given severity.
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param ... The format string, followed by the variable arguments for the format string.
|
||||
*/
|
||||
#define RCLCPP_LOG(severity, logger, ...) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
RCUTILS_LOG_NAMED(severity, (logger).get_name(), __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_ONCE
|
||||
* Log a message with given severity with the following condition:
|
||||
* - All log calls except the first one are ignored.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param ... The format string, followed by the variable arguments for the format string.
|
||||
*/
|
||||
#define RCLCPP_LOG_ONCE(severity, logger, ...) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
RCUTILS_LOG_ONCE_NAMED(severity, (logger).get_name(), __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_EXPRESSION
|
||||
* Log a message with given severity with the following condition:
|
||||
* - Log calls are ignored when the expression evaluates to false.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param expression The expression determining if the message should be logged
|
||||
* \param ... The format string, followed by the variable arguments for the format string.
|
||||
*/
|
||||
#define RCLCPP_LOG_EXPRESSION(severity, logger, expression, ...) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
RCUTILS_LOG_EXPRESSION_NAMED(severity, expression, (logger).get_name(), __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_FUNCTION
|
||||
* Log a message with given severity with the following condition:
|
||||
* - Log calls are ignored when the function returns false.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param function The functions return value determines if the message should be logged
|
||||
* \param ... The format string, followed by the variable arguments for the format string.
|
||||
*/
|
||||
#define RCLCPP_LOG_FUNCTION(severity, logger, function, ...) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
RCUTILS_LOG_FUNCTION_NAMED(severity, function, (logger).get_name(), __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_SKIPFIRST
|
||||
* Log a message with given severity with the following condition:
|
||||
* - The first log call is ignored but all subsequent calls are processed.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param ... The format string, followed by the variable arguments for the format string.
|
||||
*/
|
||||
#define RCLCPP_LOG_SKIPFIRST(severity, logger, ...) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
RCUTILS_LOG_SKIPFIRST_NAMED(severity, (logger).get_name(), __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define RCLCPP_LOG_TIME_POINT_FUNC(clock) \
|
||||
[&c = clock](rcutils_time_point_value_t * time_point)->rcutils_ret_t { \
|
||||
try { \
|
||||
*time_point = c.now().nanoseconds(); \
|
||||
} catch (...) { \
|
||||
RCUTILS_SAFE_FWRITE_TO_STDERR( \
|
||||
"[rclcpp|logging.hpp] RCLCPP_DEBUG_THROTTLE could not get current time stamp\n"); \
|
||||
return RCUTILS_RET_ERROR; \
|
||||
} \
|
||||
return RCUTILS_RET_OK; \
|
||||
}
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_THROTTLE
|
||||
* Log a message with given severity with the following condition:
|
||||
* - Log calls are ignored if the last logged message is not longer ago than the specified duration.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param clock rclcpp::Clock that will be used to get the time point.
|
||||
* \param duration The duration of the throttle interval as an integral value in milliseconds.
|
||||
* \param ... The format string, followed by the variable arguments for the format string.
|
||||
*/
|
||||
#define RCLCPP_LOG_THROTTLE(severity, logger, clock, duration, ...) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
RCUTILS_LOG_THROTTLE_NAMED( \
|
||||
severity, \
|
||||
RCLCPP_LOG_TIME_POINT_FUNC(clock), \
|
||||
duration, \
|
||||
(logger).get_name(), \
|
||||
__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_SKIPFIRST_THROTTLE
|
||||
* Log a message with given severity with the following conditions:
|
||||
* - The first log call is ignored but all subsequent calls are processed.
|
||||
* - Log calls are ignored if the last logged message is not longer ago than the specified duration.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param clock rclcpp::Clock that will be used to get the time point.
|
||||
* \param duration The duration of the throttle interval as an integral value in milliseconds.
|
||||
* \param ... The format string, followed by the variable arguments for the format string.
|
||||
*/
|
||||
#define RCLCPP_LOG_SKIPFIRST_THROTTLE(severity, logger, clock, duration, ...) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
RCUTILS_LOG_SKIPFIRST_THROTTLE_NAMED( \
|
||||
severity, \
|
||||
RCLCPP_LOG_TIME_POINT_FUNC(clock), \
|
||||
duration, \
|
||||
(logger).get_name(), \
|
||||
__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_STREAM
|
||||
* Log a message with given severity.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param stream_arg The argument << into a stringstream
|
||||
*/
|
||||
#define RCLCPP_LOG_STREAM(severity, logger, stream_arg) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
std::stringstream rclcpp_stream_ss_; \
|
||||
rclcpp_stream_ss_ << stream_arg; \
|
||||
RCUTILS_LOG_NAMED(severity, (logger).get_name(), "%s", rclcpp_stream_ss_.str().c_str()); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_STREAM_ONCE
|
||||
* Log a message with given severity with the following condition:
|
||||
* - All log calls except the first one are ignored.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param stream_arg The argument << into a stringstream
|
||||
*/
|
||||
#define RCLCPP_LOG_STREAM_ONCE(severity, logger, stream_arg) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
std::stringstream rclcpp_stream_ss_; \
|
||||
rclcpp_stream_ss_ << stream_arg; \
|
||||
RCUTILS_LOG_ONCE_NAMED(severity, (logger).get_name(), "%s", rclcpp_stream_ss_.str().c_str()); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_STREAM_EXPRESSION
|
||||
* Log a message with given severity with the following condition:
|
||||
* - Log calls are being ignored when the expression evaluates to false.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param expression The expression determining if the message should be logged
|
||||
* \param stream_arg The argument << into a stringstream
|
||||
*/
|
||||
#define RCLCPP_LOG_STREAM_EXPRESSION(severity, logger, expression, stream_arg) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
std::stringstream rclcpp_stream_ss_; \
|
||||
rclcpp_stream_ss_ << stream_arg; \
|
||||
RCUTILS_LOG_EXPRESSION_NAMED( \
|
||||
severity, \
|
||||
expression, \
|
||||
(logger).get_name(), \
|
||||
"%s", rclcpp_stream_ss_.str().c_str()); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_STREAM_FUNCTION
|
||||
* Log a message with given severity with the following condition:
|
||||
* - Log calls are being ignored when the function returns false.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param function The functions return value determines if the message should be logged
|
||||
* \param stream_arg The argument << into a stringstream
|
||||
*/
|
||||
#define RCLCPP_LOG_STREAM_FUNCTION(severity, logger, function, stream_arg) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
std::stringstream rclcpp_stream_ss_; \
|
||||
rclcpp_stream_ss_ << stream_arg; \
|
||||
RCUTILS_LOG_FUNCTION_NAMED( \
|
||||
severity, \
|
||||
function, \
|
||||
(logger).get_name(), \
|
||||
"%s", rclcpp_stream_ss_.str().c_str()); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_STREAM_SKIPFIRST
|
||||
* Log a message with given severity with the following condition:
|
||||
* - The first log call is ignored but all subsequent calls are processed.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param stream_arg The argument << into a stringstream
|
||||
*/
|
||||
#define RCLCPP_LOG_STREAM_SKIPFIRST(severity, logger, stream_arg) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
std::stringstream rclcpp_stream_ss_; \
|
||||
rclcpp_stream_ss_ << stream_arg; \
|
||||
RCUTILS_LOG_SKIPFIRST_NAMED( \
|
||||
severity, \
|
||||
(logger).get_name(), \
|
||||
"%s", rclcpp_stream_ss_.str().c_str()); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_STREAM_THROTTLE
|
||||
* Log a message with given severity with the following condition:
|
||||
* - Log calls are ignored if the last logged message is not longer ago than the specified duration.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param clock rclcpp::Clock that will be used to get the time point.
|
||||
* \param duration The duration of the throttle interval as an integral value in milliseconds.
|
||||
* \param stream_arg The argument << into a stringstream
|
||||
*/
|
||||
#define RCLCPP_LOG_STREAM_THROTTLE(severity, logger, clock, duration, stream_arg) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
std::stringstream rclcpp_stream_ss_; \
|
||||
rclcpp_stream_ss_ << stream_arg; \
|
||||
RCUTILS_LOG_THROTTLE_NAMED( \
|
||||
severity, \
|
||||
RCLCPP_LOG_TIME_POINT_FUNC(clock), \
|
||||
duration, \
|
||||
(logger).get_name(), \
|
||||
"%s", rclcpp_stream_ss_.str().c_str()); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
|
||||
* Log a message with given severity with the following conditions:
|
||||
* - The first log call is ignored but all subsequent calls are processed.
|
||||
* - Log calls are ignored if the last logged message is not longer ago than the specified duration.
|
||||
*
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
* \param clock rclcpp::Clock that will be used to get the time point.
|
||||
* \param duration The duration of the throttle interval as an integral value in milliseconds.
|
||||
* \param stream_arg The argument << into a stringstream
|
||||
*/
|
||||
#define RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(severity, logger, clock, duration, stream_arg) \
|
||||
do { \
|
||||
RCLCPP_STATIC_ASSERT_LOGGER(logger); \
|
||||
std::stringstream rclcpp_stream_ss_; \
|
||||
rclcpp_stream_ss_ << stream_arg; \
|
||||
RCUTILS_LOG_SKIPFIRST_THROTTLE_NAMED( \
|
||||
severity, \
|
||||
RCLCPP_LOG_TIME_POINT_FUNC(clock), \
|
||||
duration, \
|
||||
(logger).get_name(), \
|
||||
"%s", rclcpp_stream_ss_.str().c_str()); \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_MIN_SEVERITY
|
||||
* Define RCLCPP_LOG_MIN_SEVERITY=RCLCPP_LOG_MIN_SEVERITY_[DEBUG|INFO|WARN|ERROR|FATAL]
|
||||
* in your build options to compile out anything below that severity.
|
||||
* Use RCLCPP_LOG_MIN_SEVERITY_NONE to compile out all macros.
|
||||
*/
|
||||
#ifndef RCLCPP_LOG_MIN_SEVERITY
|
||||
#define RCLCPP_LOG_MIN_SEVERITY RCLCPP_LOG_MIN_SEVERITY_DEBUG
|
||||
#endif
|
||||
|
||||
/** @name Logging macros for severity DEBUG.
|
||||
*/
|
||||
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_DEBUG)
|
||||
// empty logging macros for severity DEBUG when being disabled at compile time
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_SKIPFIRST_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_STREAM(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_STREAM_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_STREAM_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_STREAM_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_STREAM_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_STREAM_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_DEBUG_STREAM_SKIPFIRST_THROTTLE(...)
|
||||
|
||||
#else
|
||||
/**
|
||||
* \def RCLCPP_DEBUG
|
||||
* \copydoc RCLCPP_LOG
|
||||
*/
|
||||
#define RCLCPP_DEBUG(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_DEBUG, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_ONCE
|
||||
* \copydoc RCLCPP_LOG_ONCE
|
||||
*/
|
||||
#define RCLCPP_DEBUG_ONCE(logger, ...) \
|
||||
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_DEBUG, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_DEBUG_EXPRESSION(logger, expression, ...) \
|
||||
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_DEBUG, logger, expression, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_DEBUG_FUNCTION(logger, function, ...) \
|
||||
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_DEBUG, logger, function, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_DEBUG_SKIPFIRST(logger, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_DEBUG, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_DEBUG_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_DEBUG, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_DEBUG_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_DEBUG, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_STREAM
|
||||
* \copydoc RCLCPP_LOG_STREAM
|
||||
*/
|
||||
#define RCLCPP_DEBUG_STREAM(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_DEBUG, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_STREAM_ONCE
|
||||
* \copydoc RCLCPP_LOG_STREAM_ONCE
|
||||
*/
|
||||
#define RCLCPP_DEBUG_STREAM_ONCE(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_DEBUG, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_STREAM_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_DEBUG_STREAM_EXPRESSION(logger, expression, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_DEBUG, logger, expression, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_STREAM_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_DEBUG_STREAM_FUNCTION(logger, function, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_DEBUG, logger, function, stream_args)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_STREAM_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_DEBUG_STREAM_SKIPFIRST(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_DEBUG, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_STREAM_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_DEBUG_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_DEBUG, logger, clock, duration, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_DEBUG_STREAM_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_DEBUG_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_DEBUG, logger, clock, duration, \
|
||||
stream_arg)
|
||||
|
||||
#endif
|
||||
|
||||
/** @name Logging macros for severity INFO.
|
||||
*/
|
||||
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_INFO)
|
||||
// empty logging macros for severity INFO when being disabled at compile time
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_SKIPFIRST_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_STREAM(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_STREAM_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_STREAM_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_STREAM_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_STREAM_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_STREAM_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_INFO_STREAM_SKIPFIRST_THROTTLE(...)
|
||||
|
||||
#else
|
||||
/**
|
||||
* \def RCLCPP_INFO
|
||||
* \copydoc RCLCPP_LOG
|
||||
*/
|
||||
#define RCLCPP_INFO(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_INFO, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_ONCE
|
||||
* \copydoc RCLCPP_LOG_ONCE
|
||||
*/
|
||||
#define RCLCPP_INFO_ONCE(logger, ...) \
|
||||
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_INFO, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_INFO_EXPRESSION(logger, expression, ...) \
|
||||
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_INFO, logger, expression, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_INFO_FUNCTION(logger, function, ...) \
|
||||
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_INFO, logger, function, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_INFO_SKIPFIRST(logger, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_INFO, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_INFO_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_INFO, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_INFO_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_INFO, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_STREAM
|
||||
* \copydoc RCLCPP_LOG_STREAM
|
||||
*/
|
||||
#define RCLCPP_INFO_STREAM(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_INFO, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_STREAM_ONCE
|
||||
* \copydoc RCLCPP_LOG_STREAM_ONCE
|
||||
*/
|
||||
#define RCLCPP_INFO_STREAM_ONCE(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_INFO, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_STREAM_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_INFO_STREAM_EXPRESSION(logger, expression, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_INFO, logger, expression, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_STREAM_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_INFO_STREAM_FUNCTION(logger, function, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_INFO, logger, function, stream_args)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_STREAM_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_INFO_STREAM_SKIPFIRST(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_INFO, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_STREAM_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_INFO_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_INFO, logger, clock, duration, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_INFO_STREAM_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_INFO_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_INFO, logger, clock, duration, \
|
||||
stream_arg)
|
||||
|
||||
#endif
|
||||
|
||||
/** @name Logging macros for severity WARN.
|
||||
*/
|
||||
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_WARN)
|
||||
// empty logging macros for severity WARN when being disabled at compile time
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_SKIPFIRST_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_STREAM(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_STREAM_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_STREAM_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_STREAM_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_STREAM_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_STREAM_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_WARN_STREAM_SKIPFIRST_THROTTLE(...)
|
||||
|
||||
#else
|
||||
/**
|
||||
* \def RCLCPP_WARN
|
||||
* \copydoc RCLCPP_LOG
|
||||
*/
|
||||
#define RCLCPP_WARN(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_WARN, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_ONCE
|
||||
* \copydoc RCLCPP_LOG_ONCE
|
||||
*/
|
||||
#define RCLCPP_WARN_ONCE(logger, ...) \
|
||||
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_WARN, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_WARN_EXPRESSION(logger, expression, ...) \
|
||||
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_WARN, logger, expression, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_WARN_FUNCTION(logger, function, ...) \
|
||||
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_WARN, logger, function, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_WARN_SKIPFIRST(logger, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_WARN, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_WARN_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_WARN, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_WARN_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_WARN, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_STREAM
|
||||
* \copydoc RCLCPP_LOG_STREAM
|
||||
*/
|
||||
#define RCLCPP_WARN_STREAM(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_WARN, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_STREAM_ONCE
|
||||
* \copydoc RCLCPP_LOG_STREAM_ONCE
|
||||
*/
|
||||
#define RCLCPP_WARN_STREAM_ONCE(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_WARN, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_STREAM_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_WARN_STREAM_EXPRESSION(logger, expression, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_WARN, logger, expression, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_STREAM_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_WARN_STREAM_FUNCTION(logger, function, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_WARN, logger, function, stream_args)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_STREAM_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_WARN_STREAM_SKIPFIRST(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_WARN, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_STREAM_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_WARN_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_WARN, logger, clock, duration, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_WARN_STREAM_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_WARN_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_WARN, logger, clock, duration, \
|
||||
stream_arg)
|
||||
|
||||
#endif
|
||||
|
||||
/** @name Logging macros for severity ERROR.
|
||||
*/
|
||||
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_ERROR)
|
||||
// empty logging macros for severity ERROR when being disabled at compile time
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_SKIPFIRST_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_STREAM(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_STREAM_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_STREAM_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_STREAM_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_STREAM_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_STREAM_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_ERROR_STREAM_SKIPFIRST_THROTTLE(...)
|
||||
|
||||
#else
|
||||
/**
|
||||
* \def RCLCPP_ERROR
|
||||
* \copydoc RCLCPP_LOG
|
||||
*/
|
||||
#define RCLCPP_ERROR(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_ERROR, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_ONCE
|
||||
* \copydoc RCLCPP_LOG_ONCE
|
||||
*/
|
||||
#define RCLCPP_ERROR_ONCE(logger, ...) \
|
||||
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_ERROR, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_ERROR_EXPRESSION(logger, expression, ...) \
|
||||
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_ERROR, logger, expression, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_ERROR_FUNCTION(logger, function, ...) \
|
||||
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_ERROR, logger, function, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_ERROR_SKIPFIRST(logger, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_ERROR, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_ERROR_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_ERROR, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_ERROR_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_ERROR, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_STREAM
|
||||
* \copydoc RCLCPP_LOG_STREAM
|
||||
*/
|
||||
#define RCLCPP_ERROR_STREAM(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_ERROR, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_STREAM_ONCE
|
||||
* \copydoc RCLCPP_LOG_STREAM_ONCE
|
||||
*/
|
||||
#define RCLCPP_ERROR_STREAM_ONCE(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_ERROR, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_STREAM_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_ERROR_STREAM_EXPRESSION(logger, expression, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_ERROR, logger, expression, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_STREAM_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_ERROR_STREAM_FUNCTION(logger, function, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_ERROR, logger, function, stream_args)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_STREAM_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_ERROR_STREAM_SKIPFIRST(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_ERROR, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_STREAM_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_ERROR_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_ERROR, logger, clock, duration, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_ERROR_STREAM_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_ERROR_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_ERROR, logger, clock, duration, \
|
||||
stream_arg)
|
||||
|
||||
#endif
|
||||
|
||||
/** @name Logging macros for severity FATAL.
|
||||
*/
|
||||
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_FATAL)
|
||||
// empty logging macros for severity FATAL when being disabled at compile time
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_SKIPFIRST_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_STREAM(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_STREAM_ONCE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_STREAM_EXPRESSION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_STREAM_FUNCTION(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_STREAM_SKIPFIRST(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_STREAM_THROTTLE(...)
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_FATAL_STREAM_SKIPFIRST_THROTTLE(...)
|
||||
|
||||
#else
|
||||
/**
|
||||
* \def RCLCPP_FATAL
|
||||
* \copydoc RCLCPP_LOG
|
||||
*/
|
||||
#define RCLCPP_FATAL(logger, ...) RCLCPP_LOG(RCUTILS_LOG_SEVERITY_FATAL, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_ONCE
|
||||
* \copydoc RCLCPP_LOG_ONCE
|
||||
*/
|
||||
#define RCLCPP_FATAL_ONCE(logger, ...) \
|
||||
RCLCPP_LOG_ONCE(RCUTILS_LOG_SEVERITY_FATAL, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_FATAL_EXPRESSION(logger, expression, ...) \
|
||||
RCLCPP_LOG_EXPRESSION(RCUTILS_LOG_SEVERITY_FATAL, logger, expression, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_FATAL_FUNCTION(logger, function, ...) \
|
||||
RCLCPP_LOG_FUNCTION(RCUTILS_LOG_SEVERITY_FATAL, logger, function, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_FATAL_SKIPFIRST(logger, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST(RCUTILS_LOG_SEVERITY_FATAL, logger, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_FATAL_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_THROTTLE(RCUTILS_LOG_SEVERITY_FATAL, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_FATAL_SKIPFIRST_THROTTLE(logger, clock, duration, ...) \
|
||||
RCLCPP_LOG_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_FATAL, logger, clock, duration, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_STREAM
|
||||
* \copydoc RCLCPP_LOG_STREAM
|
||||
*/
|
||||
#define RCLCPP_FATAL_STREAM(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM(RCUTILS_LOG_SEVERITY_FATAL, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_STREAM_ONCE
|
||||
* \copydoc RCLCPP_LOG_STREAM_ONCE
|
||||
*/
|
||||
#define RCLCPP_FATAL_STREAM_ONCE(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_ONCE(RCUTILS_LOG_SEVERITY_FATAL, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_STREAM_EXPRESSION
|
||||
* \copydoc RCLCPP_LOG_STREAM_EXPRESSION
|
||||
*/
|
||||
#define RCLCPP_FATAL_STREAM_EXPRESSION(logger, expression, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_EXPRESSION(RCUTILS_LOG_SEVERITY_FATAL, logger, expression, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_STREAM_FUNCTION
|
||||
* \copydoc RCLCPP_LOG_STREAM_FUNCTION
|
||||
*/
|
||||
#define RCLCPP_FATAL_STREAM_FUNCTION(logger, function, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_FUNCTION(RCUTILS_LOG_SEVERITY_FATAL, logger, function, stream_args)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_STREAM_SKIPFIRST
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST
|
||||
*/
|
||||
#define RCLCPP_FATAL_STREAM_SKIPFIRST(logger, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST(RCUTILS_LOG_SEVERITY_FATAL, logger, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_STREAM_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_FATAL_STREAM_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_THROTTLE(RCUTILS_LOG_SEVERITY_FATAL, logger, clock, duration, stream_arg)
|
||||
|
||||
/**
|
||||
* \def RCLCPP_FATAL_STREAM_SKIPFIRST_THROTTLE
|
||||
* \copydoc RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE
|
||||
*/
|
||||
#define RCLCPP_FATAL_STREAM_SKIPFIRST_THROTTLE(logger, clock, duration, stream_arg) \
|
||||
RCLCPP_LOG_STREAM_SKIPFIRST_THROTTLE(RCUTILS_LOG_SEVERITY_FATAL, logger, clock, duration, \
|
||||
stream_arg)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // RCLCPP__LOGGING_HPP_
|
||||
@@ -1388,66 +1388,6 @@ public:
|
||||
std::vector<rclcpp::TopicEndpointInfo>
|
||||
get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
|
||||
|
||||
/// Return the service endpoint information about clients on a given service.
|
||||
/**
|
||||
* The returned parameter is a list of service endpoint information, where each item will contain
|
||||
* the node name, node namespace, service type, endpoint type, endpoint count,
|
||||
* service endpoint's GIDs, and its QoS profiles.
|
||||
*
|
||||
* When the `no_mangle` parameter is `true`, the provided `service_name` should be a valid service
|
||||
* name for the middleware (useful when combining ROS with native middleware apps).
|
||||
* When the `no_mangle` parameter is `false`, the provided `service_name` should follow
|
||||
* ROS service name conventions. In DDS-based RMWs, services are implemented as topics with mangled
|
||||
* names (e.g., `rq/my_serviceRequest` and `rp/my_serviceReply`), so `no_mangle = true` is not
|
||||
* supported and will result in an error. Use `get_publishers_info_by_topic` or
|
||||
* `get_subscriptions_info_by_topic` for unmangled topic queries in such cases. Other RMWs
|
||||
* (e.g., Zenoh) may support `no_mangle = true` if they natively handle services without topic-based
|
||||
*
|
||||
* 'service_name` may be a relative, private, or fully qualified service name.
|
||||
* A relative or private service will be expanded using this node's namespace and name.
|
||||
* The queried `service_name` is not remapped.
|
||||
*
|
||||
* \param[in] service_name the actual service name used; it will not be automatically remapped.
|
||||
* \param[in] no_mangle if `true`, `service_name` needs to be a valid middleware service name,
|
||||
* otherwise it should be a valid ROS service name. Defaults to `false`.
|
||||
* \return a list of SeviceEndpointInfo representing all the clients on this service.
|
||||
* \throws InvalidServiceNameError if the given service_name is invalid.
|
||||
* \throws std::runtime_error if internal error happens.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
get_clients_info_by_service(const std::string & service_name, bool no_mangle = false) const;
|
||||
|
||||
/// Return the service endpoint information about servers on a given service.
|
||||
/**
|
||||
* The returned parameter is a list of service endpoint information, where each item will contain
|
||||
* the node name, node namespace, service type, endpoint type, endpoint count,
|
||||
* service endpoint's GIDs, and its QoS profiles.
|
||||
*
|
||||
* When the `no_mangle` parameter is `true`, the provided `service_name` should be a valid service
|
||||
* name for the middleware (useful when combining ROS with native middleware apps).
|
||||
* When the `no_mangle` parameter is `false`, the provided `service_name` should follow
|
||||
* ROS service name conventions. In DDS-based RMWs, services are implemented as topics with mangled
|
||||
* names (e.g., `rq/my_serviceRequest` and `rp/my_serviceReply`), so `no_mangle = true` is not
|
||||
* supported and will result in an error. Use `rcl_get_publishers_info_by_topic` or
|
||||
* `rcl_get_subscriptions_info_by_topic` for unmangled topic queries in such cases. Other RMWs
|
||||
* (e.g., Zenoh) may support `no_mangle = true` if they natively handle services without topic-based
|
||||
*
|
||||
* 'service_name` may be a relative, private, or fully qualified service name.
|
||||
* A relative or private service will be expanded using this node's namespace and name.
|
||||
* The queried `service_name` is not remapped.
|
||||
*
|
||||
* \param[in] service_name the actual service name used; it will not be automatically remapped.
|
||||
* \param[in] no_mangle if `true`, `service_name` needs to be a valid middleware service name,
|
||||
* otherwise it should be a valid ROS service name. Defaults to `false`.
|
||||
* \return a list of SeviceEndpointInfo representing all the servers on this service.
|
||||
* \throws InvalidServiceNameError if the given service_name is invalid.
|
||||
* \throws std::runtime_error if internal error happens.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
get_servers_info_by_service(const std::string & service_name, bool no_mangle = false) const;
|
||||
|
||||
/// Return a graph event, which will be set anytime a graph change occurs.
|
||||
/* The graph Event object is a loan which must be returned.
|
||||
* The Event object is scoped and therefore to return the loan just let it go
|
||||
|
||||
@@ -121,6 +121,11 @@ public:
|
||||
std::atomic_bool &
|
||||
get_associated_with_executor_atomic() override;
|
||||
|
||||
[[deprecated("Use get_shared_notify_guard_condition or trigger_notify_guard_condition instead")]]
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::GuardCondition &
|
||||
get_notify_guard_condition() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::GuardCondition::SharedPtr
|
||||
get_shared_notify_guard_condition() override;
|
||||
|
||||
@@ -144,6 +144,17 @@ public:
|
||||
std::atomic_bool &
|
||||
get_associated_with_executor_atomic() = 0;
|
||||
|
||||
/// Return a guard condition that should be notified when the internal node state changes.
|
||||
/**
|
||||
* For example, this should be notified when a publisher is added or removed.
|
||||
*
|
||||
* \return the GuardCondition if it is valid, else throw runtime error
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::GuardCondition &
|
||||
get_notify_guard_condition() = 0;
|
||||
|
||||
/// Return a guard condition that should be notified when the internal node state changes.
|
||||
/**
|
||||
* For example, this should be notified when a publisher is added or removed.
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rmw/service_endpoint_info_array.h"
|
||||
#include "rmw/topic_endpoint_info_array.h"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -160,24 +159,14 @@ public:
|
||||
const std::string & topic_name,
|
||||
bool no_mangle = false) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
get_clients_info_by_service(
|
||||
const std::string & service_name,
|
||||
bool no_mangle = false) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
get_servers_info_by_service(
|
||||
const std::string & service_name,
|
||||
bool no_mangle = false) const override;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeGraph)
|
||||
|
||||
/// Handle to the NodeBaseInterface given in the constructor.
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
|
||||
|
||||
/// Graph Listener which waits on graph changes for the node and is shared across nodes.
|
||||
std::shared_ptr<rclcpp::graph_listener::GraphListener> graph_listener_;
|
||||
/// Whether or not this node needs to be added to the graph listener.
|
||||
std::atomic_bool should_add_to_graph_listener_;
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
@@ -42,9 +40,7 @@ enum class EndpointType
|
||||
{
|
||||
Invalid = RMW_ENDPOINT_INVALID,
|
||||
Publisher = RMW_ENDPOINT_PUBLISHER,
|
||||
Subscription = RMW_ENDPOINT_SUBSCRIPTION,
|
||||
Client = RMW_ENDPOINT_CLIENT,
|
||||
Server = RMW_ENDPOINT_SERVER
|
||||
Subscription = RMW_ENDPOINT_SUBSCRIPTION
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -151,125 +147,6 @@ private:
|
||||
rosidl_type_hash_t topic_type_hash_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct that contains service endpoint information like the associated node name, node namespace,
|
||||
* service type, endpoint type, endpoint count, endpoint GIDs, and its QoS profiles.
|
||||
*/
|
||||
class ServiceEndpointInfo
|
||||
{
|
||||
public:
|
||||
/// Construct a ServiceEndpointInfo from a rcl_service_endpoint_info_t.
|
||||
RCLCPP_PUBLIC
|
||||
explicit ServiceEndpointInfo(const rcl_service_endpoint_info_t & info)
|
||||
: node_name_(info.node_name),
|
||||
node_namespace_(info.node_namespace),
|
||||
service_type_(info.service_type),
|
||||
endpoint_type_(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
|
||||
service_type_hash_(info.service_type_hash),
|
||||
endpoint_count_(info.endpoint_count)
|
||||
{
|
||||
for(size_t i = 0; i < endpoint_count_; i++) {
|
||||
std::array<uint8_t, RMW_GID_STORAGE_SIZE> gid;
|
||||
std::copy(info.endpoint_gids[i], info.endpoint_gids[i] + RMW_GID_STORAGE_SIZE, gid.begin());
|
||||
endpoint_gids_.push_back(gid);
|
||||
|
||||
rclcpp::QoS qos(
|
||||
{info.qos_profiles[i].history, info.qos_profiles[i].depth}, info.qos_profiles[i]);
|
||||
qos_profiles_.push_back(qos);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the node name.
|
||||
RCLCPP_PUBLIC
|
||||
std::string &
|
||||
node_name();
|
||||
|
||||
/// Get a const reference to the node name.
|
||||
RCLCPP_PUBLIC
|
||||
const std::string &
|
||||
node_name() const;
|
||||
|
||||
/// Get a mutable reference to the node namespace.
|
||||
RCLCPP_PUBLIC
|
||||
std::string &
|
||||
node_namespace();
|
||||
|
||||
/// Get a const reference to the node namespace.
|
||||
RCLCPP_PUBLIC
|
||||
const std::string &
|
||||
node_namespace() const;
|
||||
|
||||
/// Get a mutable reference to the service type string.
|
||||
RCLCPP_PUBLIC
|
||||
std::string &
|
||||
service_type();
|
||||
|
||||
/// Get a const reference to the service type string.
|
||||
RCLCPP_PUBLIC
|
||||
const std::string &
|
||||
service_type() const;
|
||||
|
||||
/// Get a mutable reference to the service endpoint type.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::EndpointType &
|
||||
endpoint_type();
|
||||
|
||||
/// Get a const reference to the service endpoint type.
|
||||
RCLCPP_PUBLIC
|
||||
const rclcpp::EndpointType &
|
||||
endpoint_type() const;
|
||||
|
||||
/// Get a mutable reference to the endpoint count.
|
||||
RCLCPP_PUBLIC
|
||||
size_t &
|
||||
endpoint_count();
|
||||
|
||||
/// Get a const reference to the endpoint count.
|
||||
RCLCPP_PUBLIC
|
||||
const size_t &
|
||||
endpoint_count() const;
|
||||
|
||||
/// Get a mutable reference to the GID of the service endpoint.
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
|
||||
endpoint_gids();
|
||||
|
||||
/// Get a const reference to the GID of the service endpoint.
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
|
||||
endpoint_gids() const;
|
||||
|
||||
/// Get a mutable reference to the QoS profile of the service endpoint.
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::QoS> &
|
||||
qos_profiles();
|
||||
|
||||
/// Get a const reference to the QoS profile of the service endpoint.
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::QoS> &
|
||||
qos_profiles() const;
|
||||
|
||||
/// Get a mutable reference to the type hash of the service endpoint.
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_type_hash_t &
|
||||
service_type_hash();
|
||||
|
||||
/// Get a const reference to the type hash of the service endpoint.
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_type_hash_t &
|
||||
service_type_hash() const;
|
||||
|
||||
private:
|
||||
std::string node_name_;
|
||||
std::string node_namespace_;
|
||||
std::string service_type_;
|
||||
rclcpp::EndpointType endpoint_type_;
|
||||
std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> endpoint_gids_;
|
||||
std::vector<rclcpp::QoS> qos_profiles_;
|
||||
rosidl_type_hash_t service_type_hash_;
|
||||
size_t endpoint_count_;
|
||||
};
|
||||
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
@@ -535,30 +412,6 @@ public:
|
||||
virtual
|
||||
std::vector<rclcpp::TopicEndpointInfo>
|
||||
get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
|
||||
|
||||
/// Return the service endpoint information about clients on a given service.
|
||||
/**
|
||||
* \param[in] service_name the actual service name used; it will not be automatically remapped.
|
||||
* \param[in] no_mangle if `true`, `service_name` needs to be a valid middleware service name,
|
||||
* otherwise it should be a valid ROS service name.
|
||||
* \sa rclcpp::Node::get_clients_info_by_service
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
get_clients_info_by_service(const std::string & service_name, bool no_mangle = false) const = 0;
|
||||
|
||||
/// Return the service endpoint information about servers on a given service.
|
||||
/**
|
||||
* \param[in] service_name the actual service name used; it will not be automatically remapped.
|
||||
* \param[in] no_mangle if `true`, `service_name` needs to be a valid middleware service name,
|
||||
* otherwise it should be a valid ROS service name.
|
||||
* \sa rclcpp::Node::get_servers_info_by_service
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
get_servers_info_by_service(const std::string & service_name, bool no_mangle = false) const = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
// 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__PARAMETER_DESCRIPTOR_WRAPPER_HPP_
|
||||
#define RCLCPP__PARAMETER_DESCRIPTOR_WRAPPER_HPP_
|
||||
|
||||
// C++ Standard library includes
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// Additional ROS libraries needed
|
||||
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
|
||||
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/parameter_value.hpp"
|
||||
#include "rclcpp/node_interfaces/get_node_parameters_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "node_interfaces/node_parameters_interface.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
// Implements ParameterDesription class with builder design pattern
|
||||
class ParameterDescription
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(ParameterDescription)
|
||||
|
||||
// List of classes the builder manages
|
||||
RCLCPP_PUBLIC
|
||||
ParameterDescription();
|
||||
|
||||
// Our Main build methods which will construct the base class
|
||||
RCLCPP_PUBLIC rcl_interfaces::msg::ParameterDescriptor build() const;
|
||||
|
||||
// Builder Methods:
|
||||
// Describes the instances in a parameter_description object
|
||||
RCLCPP_PUBLIC ParameterDescription & set_name(const std::string & name);
|
||||
RCLCPP_PUBLIC ParameterDescription & set_type(std::uint8_t type);
|
||||
RCLCPP_PUBLIC ParameterDescription & set_description_text(const std::string & description);
|
||||
RCLCPP_PUBLIC ParameterDescription & set_additional_constraints(const std::string & constraints);
|
||||
RCLCPP_PUBLIC ParameterDescription & set_read_only(bool read_only);
|
||||
RCLCPP_PUBLIC ParameterDescription & set_dynamic_typing(bool dynamic_typing);
|
||||
RCLCPP_PUBLIC ParameterDescription & set_floating_point_description_range(
|
||||
float min, float max, float step);
|
||||
RCLCPP_PUBLIC ParameterDescription & set_integer_description_range(int min, int max, int step);
|
||||
|
||||
// Need the current node in order to begin the configuration state
|
||||
// for it via the declare_parameter function
|
||||
template<typename NodeT>
|
||||
ParameterDescription & declare_parameter(
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
NodeT && node)
|
||||
{
|
||||
auto node_param = rclcpp::node_interfaces::get_node_parameters_interface(node);
|
||||
node_param->declare_parameter(
|
||||
parameter_descriptor.name, default_value,
|
||||
parameter_descriptor);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// The main descriptor object we're meant to initialize and adjust
|
||||
rcl_interfaces::msg::ParameterDescriptor parameter_descriptor;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__PARAMETER_DESCRIPTOR_WRAPPER_HPP_
|
||||
@@ -234,10 +234,6 @@ public:
|
||||
/**
|
||||
* If a node_name is not provided, defaults to the current node.
|
||||
*
|
||||
* The configure_nodes_filter() function will affect the behavior of this function.
|
||||
* If the node specified in this function isn't included in the nodes specified in
|
||||
* configure_nodes_filter(), the callback will never be called.
|
||||
*
|
||||
* Note: if the returned callback handle smart pointer is not captured, the callback
|
||||
* is immediately unregistered. A compiler warning should be generated to warn
|
||||
* of this.
|
||||
@@ -255,31 +251,6 @@ public:
|
||||
ParameterCallbackType callback,
|
||||
const std::string & node_name = "");
|
||||
|
||||
/// Configure which node parameter events will be received.
|
||||
/**
|
||||
* This function depends on rmw implementation support for content filtering.
|
||||
* If middleware doesn't support contentfilter, return false.
|
||||
*
|
||||
* If node_names is empty, the configured node filter will be cleared.
|
||||
*
|
||||
* If this function return true, only parameter events from the specified node will be received.
|
||||
* It affects the behavior of the following two functions.
|
||||
* - add_parameter_event_callback()
|
||||
* The callback will only be called for parameter events from the specified nodes which are
|
||||
* configured in this function.
|
||||
* - add_parameter_callback()
|
||||
* The callback will only be called for parameter events from the specified nodes which are
|
||||
* configured in this function and add_parameter_callback().
|
||||
* If the nodes specified in this function is different from the nodes specified in
|
||||
* add_parameter_callback(), the callback will never be called.
|
||||
*
|
||||
* \param[in] node_names Node names to filter parameter events from.
|
||||
* \returns true if configuring was successfully applied, false otherwise.
|
||||
* \throws rclcpp::exceptions::RCLError if internal error occurred when calling the rcl function.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool configure_nodes_filter(const std::vector<std::string> & node_names);
|
||||
|
||||
/// Remove a parameter callback registered with add_parameter_callback.
|
||||
/**
|
||||
* The parameter name and node name are inspected from the callback handle. The callback handle
|
||||
|
||||
@@ -574,13 +574,6 @@ protected:
|
||||
std::unique_ptr<PublishedType, PublishedTypeDeleter>
|
||||
duplicate_type_adapt_message_as_unique_ptr(const PublishedType & msg)
|
||||
{
|
||||
/// Assert that the published type has no overloaded operator new since this leads to
|
||||
/// new/delete mismatch (see https://github.com/ros2/rclcpp/issues/2951)
|
||||
static_assert(!detail::has_overloaded_operator_new_v<PublishedType>,
|
||||
"When publishing by value (i.e. when calling publish(const T& msg)), the published "
|
||||
"message type must not have an overloaded operator new. In this case, please use the "
|
||||
"publish(std::unique_ptr<T> msg) method instead.");
|
||||
|
||||
auto ptr = PublishedTypeAllocatorTraits::allocate(published_type_allocator_, 1);
|
||||
PublishedTypeAllocatorTraits::construct(published_type_allocator_, ptr, msg);
|
||||
return std::unique_ptr<PublishedType, PublishedTypeDeleter>(ptr, published_type_deleter_);
|
||||
|
||||
@@ -68,6 +68,8 @@
|
||||
*
|
||||
* - Executors (responsible for execution of callbacks through a blocking spin):
|
||||
* - rclcpp::spin()
|
||||
* - rclcpp::spin_some()
|
||||
* - rclcpp::spin_until_future_complete()
|
||||
* - rclcpp::executors::SingleThreadedExecutor
|
||||
* - rclcpp::executors::SingleThreadedExecutor::add_node()
|
||||
* - rclcpp::executors::SingleThreadedExecutor::spin()
|
||||
@@ -175,7 +177,6 @@
|
||||
#include "rclcpp/parameter_event_handler.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/parameter_service.hpp"
|
||||
#include "rclcpp/parameter_descriptor_wrapper.hpp"
|
||||
#include "rclcpp/rate.hpp"
|
||||
#include "rclcpp/time.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
|
||||
@@ -99,92 +99,49 @@ public:
|
||||
// Important to use subscription_handles_.size() instead of wait set's size since
|
||||
// there may be more subscriptions in the wait set due to Waitables added to the end.
|
||||
// The same logic applies for other entities.
|
||||
|
||||
// Mark corresponding weak_ptr as expired for entities that are null in the wait set
|
||||
size_t valid_subscription_count = 0;
|
||||
for (size_t i = 0; i < subscription_handles_.size(); ++i) {
|
||||
if (valid_subscription_count < wait_set->size_of_subscriptions &&
|
||||
!wait_set->subscriptions[valid_subscription_count])
|
||||
{
|
||||
subscription_handles_[i] = std::weak_ptr<const rcl_subscription_t>{};
|
||||
}
|
||||
if (subscription_handles_[i].lock()) {
|
||||
++valid_subscription_count;
|
||||
if (!wait_set->subscriptions[i]) {
|
||||
subscription_handles_[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
size_t valid_service_count = 0;
|
||||
for (size_t i = 0; i < service_handles_.size(); ++i) {
|
||||
if (valid_service_count < wait_set->size_of_services &&
|
||||
!wait_set->services[valid_service_count])
|
||||
{
|
||||
service_handles_[i] = std::weak_ptr<const rcl_service_t>{};
|
||||
}
|
||||
if (service_handles_[i].lock()) {
|
||||
++valid_service_count;
|
||||
if (!wait_set->services[i]) {
|
||||
service_handles_[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
size_t valid_client_count = 0;
|
||||
for (size_t i = 0; i < client_handles_.size(); ++i) {
|
||||
if (valid_client_count < wait_set->size_of_clients &&
|
||||
!wait_set->clients[valid_client_count])
|
||||
{
|
||||
client_handles_[i] = std::weak_ptr<const rcl_client_t>{};
|
||||
}
|
||||
if (client_handles_[i].lock()) {
|
||||
++valid_client_count;
|
||||
if (!wait_set->clients[i]) {
|
||||
client_handles_[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
size_t valid_timer_count = 0;
|
||||
for (size_t i = 0; i < timer_handles_.size(); ++i) {
|
||||
if (valid_timer_count < wait_set->size_of_timers &&
|
||||
!wait_set->timers[valid_timer_count])
|
||||
{
|
||||
timer_handles_[i] = std::weak_ptr<const rcl_timer_t>{};
|
||||
}
|
||||
if (timer_handles_[i].lock()) {
|
||||
++valid_timer_count;
|
||||
if (!wait_set->timers[i]) {
|
||||
timer_handles_[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < waitable_handles_.size(); ++i) {
|
||||
if (!waitable_handles_[i]->is_ready(*wait_set)) {
|
||||
waitable_handles_[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove expired weak_ptr instances
|
||||
subscription_handles_.erase(
|
||||
std::remove_if(subscription_handles_.begin(), subscription_handles_.end(),
|
||||
[](const std::weak_ptr<const rcl_subscription_t> & weak_ptr) {
|
||||
return weak_ptr.expired();
|
||||
}),
|
||||
std::remove(subscription_handles_.begin(), subscription_handles_.end(), nullptr),
|
||||
subscription_handles_.end()
|
||||
);
|
||||
|
||||
service_handles_.erase(
|
||||
std::remove_if(service_handles_.begin(), service_handles_.end(),
|
||||
[](const std::weak_ptr<const rcl_service_t> & weak_ptr) {
|
||||
return weak_ptr.expired();
|
||||
}),
|
||||
std::remove(service_handles_.begin(), service_handles_.end(), nullptr),
|
||||
service_handles_.end()
|
||||
);
|
||||
|
||||
client_handles_.erase(
|
||||
std::remove_if(client_handles_.begin(), client_handles_.end(),
|
||||
[](const std::weak_ptr<const rcl_client_t> & weak_ptr) {
|
||||
return weak_ptr.expired();
|
||||
}),
|
||||
std::remove(client_handles_.begin(), client_handles_.end(), nullptr),
|
||||
client_handles_.end()
|
||||
);
|
||||
|
||||
timer_handles_.erase(
|
||||
std::remove_if(timer_handles_.begin(), timer_handles_.end(),
|
||||
[](const std::weak_ptr<const rcl_timer_t> & weak_ptr) {
|
||||
return weak_ptr.expired();
|
||||
}),
|
||||
std::remove(timer_handles_.begin(), timer_handles_.end(), nullptr),
|
||||
timer_handles_.end()
|
||||
);
|
||||
|
||||
@@ -239,13 +196,7 @@ public:
|
||||
|
||||
bool add_handles_to_wait_set(rcl_wait_set_t * wait_set) override
|
||||
{
|
||||
for (const std::weak_ptr<const rcl_subscription_t> & weak_subscription :
|
||||
subscription_handles_)
|
||||
{
|
||||
auto subscription = weak_subscription.lock();
|
||||
if (!subscription) {
|
||||
continue; // Skip expired handles
|
||||
}
|
||||
for (const std::shared_ptr<const rcl_subscription_t> & subscription : subscription_handles_) {
|
||||
if (rcl_wait_set_add_subscription(wait_set, subscription.get(), NULL) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
@@ -255,11 +206,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::weak_ptr<const rcl_client_t> & weak_client : client_handles_) {
|
||||
auto client = weak_client.lock();
|
||||
if (!client) {
|
||||
continue; // Skip expired handles
|
||||
}
|
||||
for (const std::shared_ptr<const rcl_client_t> & client : client_handles_) {
|
||||
if (rcl_wait_set_add_client(wait_set, client.get(), NULL) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
@@ -269,11 +216,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::weak_ptr<const rcl_service_t> & weak_service : service_handles_) {
|
||||
auto service = weak_service.lock();
|
||||
if (!service) {
|
||||
continue; // Skip expired handles
|
||||
}
|
||||
for (const std::shared_ptr<const rcl_service_t> & service : service_handles_) {
|
||||
if (rcl_wait_set_add_service(wait_set, service.get(), NULL) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
@@ -283,11 +226,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::weak_ptr<const rcl_timer_t> & weak_timer : timer_handles_) {
|
||||
auto timer = weak_timer.lock();
|
||||
if (!timer) {
|
||||
continue; // Skip expired handles
|
||||
}
|
||||
for (const std::shared_ptr<const rcl_timer_t> & timer : timer_handles_) {
|
||||
if (rcl_wait_set_add_timer(wait_set, timer.get(), NULL) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
@@ -314,13 +253,7 @@ public:
|
||||
{
|
||||
auto it = subscription_handles_.begin();
|
||||
while (it != subscription_handles_.end()) {
|
||||
auto subscription_handle = it->lock();
|
||||
if (!subscription_handle) {
|
||||
// Handle expired, remove it and continue
|
||||
it = subscription_handles_.erase(it);
|
||||
continue;
|
||||
}
|
||||
auto subscription = get_subscription_by_handle(subscription_handle, weak_groups_to_nodes);
|
||||
auto subscription = get_subscription_by_handle(*it, weak_groups_to_nodes);
|
||||
if (subscription) {
|
||||
// Find the group for this handle and see if it can be serviced
|
||||
auto group = get_group_by_subscription(subscription, weak_groups_to_nodes);
|
||||
@@ -355,13 +288,7 @@ public:
|
||||
{
|
||||
auto it = service_handles_.begin();
|
||||
while (it != service_handles_.end()) {
|
||||
auto service_handle = it->lock();
|
||||
if (!service_handle) {
|
||||
// Handle expired, remove it and continue
|
||||
it = service_handles_.erase(it);
|
||||
continue;
|
||||
}
|
||||
auto service = get_service_by_handle(service_handle, weak_groups_to_nodes);
|
||||
auto service = get_service_by_handle(*it, weak_groups_to_nodes);
|
||||
if (service) {
|
||||
// Find the group for this handle and see if it can be serviced
|
||||
auto group = get_group_by_service(service, weak_groups_to_nodes);
|
||||
@@ -396,13 +323,7 @@ public:
|
||||
{
|
||||
auto it = client_handles_.begin();
|
||||
while (it != client_handles_.end()) {
|
||||
auto client_handle = it->lock();
|
||||
if (!client_handle) {
|
||||
// Handle expired, remove it and continue
|
||||
it = client_handles_.erase(it);
|
||||
continue;
|
||||
}
|
||||
auto client = get_client_by_handle(client_handle, weak_groups_to_nodes);
|
||||
auto client = get_client_by_handle(*it, weak_groups_to_nodes);
|
||||
if (client) {
|
||||
// Find the group for this handle and see if it can be serviced
|
||||
auto group = get_group_by_client(client, weak_groups_to_nodes);
|
||||
@@ -437,13 +358,7 @@ public:
|
||||
{
|
||||
auto it = timer_handles_.begin();
|
||||
while (it != timer_handles_.end()) {
|
||||
auto timer_handle = it->lock();
|
||||
if (!timer_handle) {
|
||||
// Handle expired, remove it and continue
|
||||
it = timer_handles_.erase(it);
|
||||
continue;
|
||||
}
|
||||
auto timer = get_timer_by_handle(timer_handle, weak_groups_to_nodes);
|
||||
auto timer = get_timer_by_handle(*it, weak_groups_to_nodes);
|
||||
if (timer) {
|
||||
// Find the group for this handle and see if it can be serviced
|
||||
auto group = get_group_by_timer(timer, weak_groups_to_nodes);
|
||||
@@ -520,13 +435,7 @@ public:
|
||||
|
||||
size_t number_of_ready_subscriptions() const override
|
||||
{
|
||||
size_t number_of_subscriptions = 0;
|
||||
// Count only non-expired weak_ptr references
|
||||
for (const auto & weak_subscription : subscription_handles_) {
|
||||
if (!weak_subscription.expired()) {
|
||||
++number_of_subscriptions;
|
||||
}
|
||||
}
|
||||
size_t number_of_subscriptions = subscription_handles_.size();
|
||||
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
|
||||
number_of_subscriptions += waitable->get_number_of_ready_subscriptions();
|
||||
}
|
||||
@@ -535,13 +444,7 @@ public:
|
||||
|
||||
size_t number_of_ready_services() const override
|
||||
{
|
||||
size_t number_of_services = 0;
|
||||
// Count only non-expired weak_ptr references
|
||||
for (const auto & weak_service : service_handles_) {
|
||||
if (!weak_service.expired()) {
|
||||
++number_of_services;
|
||||
}
|
||||
}
|
||||
size_t number_of_services = service_handles_.size();
|
||||
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
|
||||
number_of_services += waitable->get_number_of_ready_services();
|
||||
}
|
||||
@@ -559,13 +462,7 @@ public:
|
||||
|
||||
size_t number_of_ready_clients() const override
|
||||
{
|
||||
size_t number_of_clients = 0;
|
||||
// Count only non-expired weak_ptr references
|
||||
for (const auto & weak_client : client_handles_) {
|
||||
if (!weak_client.expired()) {
|
||||
++number_of_clients;
|
||||
}
|
||||
}
|
||||
size_t number_of_clients = client_handles_.size();
|
||||
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
|
||||
number_of_clients += waitable->get_number_of_ready_clients();
|
||||
}
|
||||
@@ -583,13 +480,7 @@ public:
|
||||
|
||||
size_t number_of_ready_timers() const override
|
||||
{
|
||||
size_t number_of_timers = 0;
|
||||
// Count only non-expired weak_ptr references
|
||||
for (const auto & weak_timer : timer_handles_) {
|
||||
if (!weak_timer.expired()) {
|
||||
++number_of_timers;
|
||||
}
|
||||
}
|
||||
size_t number_of_timers = timer_handles_.size();
|
||||
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
|
||||
number_of_timers += waitable->get_number_of_ready_timers();
|
||||
}
|
||||
@@ -608,10 +499,10 @@ private:
|
||||
|
||||
VectorRebind<const rclcpp::GuardCondition *> guard_conditions_;
|
||||
|
||||
VectorRebind<std::weak_ptr<const rcl_subscription_t>> subscription_handles_;
|
||||
VectorRebind<std::weak_ptr<const rcl_service_t>> service_handles_;
|
||||
VectorRebind<std::weak_ptr<const rcl_client_t>> client_handles_;
|
||||
VectorRebind<std::weak_ptr<const rcl_timer_t>> timer_handles_;
|
||||
VectorRebind<std::shared_ptr<const rcl_subscription_t>> subscription_handles_;
|
||||
VectorRebind<std::shared_ptr<const rcl_service_t>> service_handles_;
|
||||
VectorRebind<std::shared_ptr<const rcl_client_t>> client_handles_;
|
||||
VectorRebind<std::shared_ptr<const rcl_timer_t>> timer_handles_;
|
||||
VectorRebind<std::shared_ptr<Waitable>> waitable_handles_;
|
||||
|
||||
std::shared_ptr<VoidAlloc> allocator_;
|
||||
|
||||
@@ -279,50 +279,6 @@ public:
|
||||
return message_memory_strategy_->borrow_serialized_message();
|
||||
}
|
||||
|
||||
/// Disable callbacks from being called
|
||||
/**
|
||||
* This method will block, until any subscription's callbacks provided during construction
|
||||
* currently being executed are finished.
|
||||
* \note This method also temporary removes the on new message callback and all
|
||||
* on new event callbacks from the rmw layer to prevent them from being called. However, this
|
||||
* method will not block and wait until the currently executing on_new_[message]event callbacks
|
||||
* are finished.
|
||||
*/
|
||||
void
|
||||
disable_callbacks() override
|
||||
{
|
||||
SubscriptionBase::disable_callbacks();
|
||||
any_callback_.disable();
|
||||
if (subscription_intra_process_) {
|
||||
subscription_intra_process_->disable_callbacks();
|
||||
}
|
||||
for (const auto & [_, event_ptr] : event_handlers_) {
|
||||
if (event_ptr) {
|
||||
event_ptr->disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable the callbacks to be called
|
||||
/**
|
||||
* This method is thread safe, and provides a safe way to atomically enable the callbacks
|
||||
* in a multithreaded environment.
|
||||
*/
|
||||
void
|
||||
enable_callbacks() override
|
||||
{
|
||||
SubscriptionBase::enable_callbacks();
|
||||
any_callback_.enable();
|
||||
if (subscription_intra_process_) {
|
||||
subscription_intra_process_->enable_callbacks();
|
||||
}
|
||||
for (const auto & [_, event_ptr] : event_handlers_) {
|
||||
if (event_ptr) {
|
||||
event_ptr->enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_message(
|
||||
std::shared_ptr<void> & message,
|
||||
|
||||
@@ -212,23 +212,6 @@ public:
|
||||
std::shared_ptr<rclcpp::SerializedMessage>
|
||||
create_serialized_message() = 0;
|
||||
|
||||
/// Disable callbacks from being called
|
||||
/**
|
||||
* This function temporary removes the on_new_message_callback to prevent it from being called.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void disable_callbacks();
|
||||
|
||||
/// Enable the callbacks to be called
|
||||
/**
|
||||
* This function sets back the on_new_message_callback if it was previously removed in
|
||||
* disable_callbacks().
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void enable_callbacks();
|
||||
|
||||
/// Check if we need to handle the message, and execute the callback if we do.
|
||||
/**
|
||||
* \param[in] message Shared pointer to the message to handle.
|
||||
@@ -400,7 +383,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
|
||||
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
|
||||
@@ -423,7 +406,7 @@ public:
|
||||
void
|
||||
clear_on_new_message_callback()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
|
||||
if (on_new_message_callback_) {
|
||||
set_on_new_message_callback(nullptr, nullptr);
|
||||
@@ -663,7 +646,7 @@ protected:
|
||||
|
||||
std::shared_ptr<rcl_node_t> node_handle_;
|
||||
|
||||
std::recursive_mutex on_new_message_callback_mutex_;
|
||||
std::recursive_mutex callback_mutex_;
|
||||
// It is important to declare on_new_message_callback_ before
|
||||
// subscription_handle_, so on destruction the subscription is
|
||||
// destroyed first. Otherwise, the rmw subscription callback
|
||||
|
||||
@@ -33,11 +33,12 @@ class Time
|
||||
public:
|
||||
/// Time constructor
|
||||
/**
|
||||
* Indicates a specific point in time, relative to a clock's 0 point (its epoch).
|
||||
* The total time since the epoch is given by seconds + nanoseconds.
|
||||
* Initializes the time values for seconds and nanoseconds individually.
|
||||
* Large values for nanoseconds are wrapped automatically with the remainder added to seconds.
|
||||
* Both inputs must be integers.
|
||||
*
|
||||
* \param seconds the seconds component, valid only if positive
|
||||
* \param nanoseconds the nanoseconds component, to be added to the seconds component
|
||||
* \param seconds part of the time in seconds since time epoch
|
||||
* \param nanoseconds part of the time in nanoseconds since time epoch
|
||||
* \param clock_type clock type
|
||||
* \throws std::runtime_error if seconds are negative
|
||||
*/
|
||||
@@ -46,7 +47,7 @@ public:
|
||||
|
||||
/// Time constructor
|
||||
/**
|
||||
* \param nanoseconds the total time since the epoch in nanoseconds
|
||||
* \param nanoseconds since time epoch
|
||||
* \param clock_type clock type
|
||||
* \throws std::runtime_error if nanoseconds are negative
|
||||
*/
|
||||
@@ -189,7 +190,7 @@ public:
|
||||
|
||||
/// Get the nanoseconds since epoch
|
||||
/**
|
||||
* \return the total time since the epoch in nanoseconds, as a rcl_time_point_value_t structure.
|
||||
* \return the nanoseconds since epoch as a rcl_time_point_value_t structure.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rcl_time_point_value_t
|
||||
@@ -208,7 +209,7 @@ public:
|
||||
* \warning Depending on sizeof(double) there could be significant precision loss.
|
||||
* When an exact time is required use nanoseconds() instead.
|
||||
*
|
||||
* \return the total time since the epoch in seconds, as a floating point number.
|
||||
* \return the seconds since epoch as a floating point number.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
double
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#define RCLCPP__TYPE_ADAPTER_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
#include <new>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
@@ -129,24 +128,6 @@ struct assert_type_pair_is_specialized_type_adapter
|
||||
"No type adapter for this custom type/ros message type pair");
|
||||
};
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_overloaded_operator_new : std::false_type {};
|
||||
template<typename T>
|
||||
struct has_overloaded_operator_new<T, std::void_t<
|
||||
decltype(T::operator new(std::size_t()))
|
||||
>>: std::true_type {};
|
||||
|
||||
template<typename, typename = void>
|
||||
struct has_overloaded_aligned_operator_new : std::false_type {};
|
||||
template<typename T>
|
||||
struct has_overloaded_aligned_operator_new<T,
|
||||
std::void_t<decltype( T::operator new(std::size_t(), std::align_val_t()) )>>
|
||||
: std::true_type {};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool has_overloaded_operator_new_v = has_overloaded_operator_new<T>::value ||
|
||||
has_overloaded_aligned_operator_new<T>::value;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Template metafunction that can make the type being adapted explicit.
|
||||
|
||||
@@ -704,12 +704,10 @@ public:
|
||||
return WaitResult<WaitSetTemplate>::from_timeout_wait_result_kind();
|
||||
case WaitResultKind::Empty:
|
||||
return WaitResult<WaitSetTemplate>::from_empty_wait_result_kind();
|
||||
case WaitResultKind::Invalid:
|
||||
auto msg = "invalid WaitResultKind with value: " + std::to_string(wait_result_kind);
|
||||
default:
|
||||
auto msg = "unknown WaitResultKind with value: " + std::to_string(wait_result_kind);
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
// This should never be reached, but is needed to satisfy the compiler
|
||||
throw std::runtime_error("unreachable code in wait result kind switch");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp</name>
|
||||
<version>30.1.5</version>
|
||||
<version>29.5.7</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
@@ -17,7 +17,6 @@
|
||||
<buildtool_depend>ament_cmake_ros</buildtool_depend>
|
||||
<buildtool_depend>ament_cmake_gen_version_h</buildtool_depend>
|
||||
<buildtool_depend>python3</buildtool_depend>
|
||||
<buildtool_depend>python3-empy</buildtool_depend>
|
||||
|
||||
<build_depend>ament_index_cpp</build_depend>
|
||||
<build_depend>builtin_interfaces</build_depend>
|
||||
@@ -47,9 +46,9 @@
|
||||
<depend>statistics_msgs</depend>
|
||||
<depend>tracetools</depend>
|
||||
|
||||
<test_depend>ament_cmake_gmock</test_depend>
|
||||
<test_depend>ament_cmake_google_benchmark</test_depend>
|
||||
<test_depend>ament_cmake_gtest</test_depend>
|
||||
<test_depend>ament_cmake_ros</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
<test_depend>mimick_vendor</test_depend>
|
||||
|
||||
164
rclcpp/resource/logging.hpp.em
Normal file
164
rclcpp/resource/logging.hpp.em
Normal file
@@ -0,0 +1,164 @@
|
||||
// generated from rclcpp/resource/logging.hpp.em
|
||||
|
||||
// Copyright 2017 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__LOGGING_HPP_
|
||||
#define RCLCPP__LOGGING_HPP_
|
||||
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rcutils/logging_macros.h"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
|
||||
// These are used for compiling out logging macros lower than a minimum severity.
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_DEBUG 0
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_INFO 1
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_WARN 2
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_ERROR 3
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_FATAL 4
|
||||
#define RCLCPP_LOG_MIN_SEVERITY_NONE 5
|
||||
|
||||
#define RCLCPP_FIRST_ARG(N, ...) N
|
||||
#define RCLCPP_ALL_BUT_FIRST_ARGS(N, ...) __VA_ARGS__
|
||||
|
||||
/**
|
||||
* \def RCLCPP_LOG_MIN_SEVERITY
|
||||
* Define RCLCPP_LOG_MIN_SEVERITY=RCLCPP_LOG_MIN_SEVERITY_[DEBUG|INFO|WARN|ERROR|FATAL]
|
||||
* in your build options to compile out anything below that severity.
|
||||
* Use RCLCPP_LOG_MIN_SEVERITY_NONE to compile out all macros.
|
||||
*/
|
||||
#ifndef RCLCPP_LOG_MIN_SEVERITY
|
||||
#define RCLCPP_LOG_MIN_SEVERITY RCLCPP_LOG_MIN_SEVERITY_DEBUG
|
||||
#endif
|
||||
|
||||
@{
|
||||
from collections import OrderedDict
|
||||
from copy import deepcopy
|
||||
from rcutils.logging import feature_combinations
|
||||
from rcutils.logging import get_suffix_from_features
|
||||
from rcutils.logging import severities
|
||||
from rcutils.logging import throttle_args
|
||||
from rcutils.logging import throttle_params
|
||||
|
||||
throttle_args['condition_before'] = 'RCUTILS_LOG_CONDITION_THROTTLE_BEFORE(clock, duration)'
|
||||
del throttle_params['get_time_point_value']
|
||||
throttle_params['clock'] = 'rclcpp::Clock that will be used to get the time point.'
|
||||
throttle_params.move_to_end('clock', last=False)
|
||||
|
||||
rclcpp_feature_combinations = OrderedDict()
|
||||
for combinations, feature in feature_combinations.items():
|
||||
# skip feature combinations using 'named'
|
||||
if 'named' in combinations:
|
||||
continue
|
||||
rclcpp_feature_combinations[combinations] = feature
|
||||
# add a stream variant for each available feature combination
|
||||
stream_arg = 'stream_arg'
|
||||
for combinations, feature in list(rclcpp_feature_combinations.items()):
|
||||
combinations = ('stream', ) + combinations
|
||||
feature = deepcopy(feature)
|
||||
feature.params[stream_arg] = 'The argument << into a stringstream'
|
||||
rclcpp_feature_combinations[combinations] = feature
|
||||
|
||||
def get_rclcpp_suffix_from_features(features):
|
||||
suffix = get_suffix_from_features(features)
|
||||
if 'stream' in features:
|
||||
suffix = '_STREAM' + suffix
|
||||
return suffix
|
||||
}@
|
||||
@[for severity in severities]@
|
||||
/** @@name Logging macros for severity @(severity).
|
||||
*/
|
||||
///@@{
|
||||
#if (RCLCPP_LOG_MIN_SEVERITY > RCLCPP_LOG_MIN_SEVERITY_@(severity))
|
||||
// empty logging macros for severity @(severity) when being disabled at compile time
|
||||
@[ for feature_combination in rclcpp_feature_combinations.keys()]@
|
||||
@{suffix = get_rclcpp_suffix_from_features(feature_combination)}@
|
||||
/// Empty logging macro due to the preprocessor definition of RCLCPP_LOG_MIN_SEVERITY.
|
||||
#define RCLCPP_@(severity)@(suffix)(...)
|
||||
@[ end for]@
|
||||
|
||||
#else
|
||||
@[ for feature_combination in rclcpp_feature_combinations.keys()]@
|
||||
@{suffix = get_rclcpp_suffix_from_features(feature_combination)}@
|
||||
// The RCLCPP_@(severity)@(suffix) macro is surrounded by do { .. } while (0)
|
||||
// to implement the standard C macro idiom to make the macro safe in all
|
||||
// contexts; see http://c-faq.com/cpp/multistmt.html for more information.
|
||||
/**
|
||||
* \def RCLCPP_@(severity)@(suffix)
|
||||
* Log a message with severity @(severity)@
|
||||
@[ if rclcpp_feature_combinations[feature_combination].doc_lines]@
|
||||
with the following conditions:
|
||||
@[ else]@
|
||||
.
|
||||
@[ end if]@
|
||||
@[ for doc_line in rclcpp_feature_combinations[feature_combination].doc_lines]@
|
||||
* @(doc_line)
|
||||
@[ end for]@
|
||||
* \param logger The `rclcpp::Logger` to use
|
||||
@[ for param_name, doc_line in rclcpp_feature_combinations[feature_combination].params.items()]@
|
||||
* \param @(param_name) @(doc_line)
|
||||
@[ end for]@
|
||||
@[ if 'stream' not in feature_combination]@
|
||||
* \param ... The format string, followed by the variable arguments for the format string.
|
||||
@[ end if]@
|
||||
*/
|
||||
@{params = rclcpp_feature_combinations[feature_combination].params.keys()}@
|
||||
#define RCLCPP_@(severity)@(suffix)(logger@(''.join([', ' + p for p in params]))@
|
||||
@[ if 'stream' not in feature_combination]@
|
||||
, ...@
|
||||
@[ end if]@
|
||||
) \
|
||||
do { \
|
||||
static_assert( \
|
||||
::std::is_convertible_v<decltype(logger), ::rclcpp::Logger>, \
|
||||
"First argument to logging macros must be an rclcpp::Logger"); \
|
||||
@[ if 'throttle' in feature_combination]@ \
|
||||
auto get_time_point = [&c=clock](rcutils_time_point_value_t * time_point) -> rcutils_ret_t { \
|
||||
try { \
|
||||
*time_point = c.now().nanoseconds(); \
|
||||
} catch (...) { \
|
||||
RCUTILS_SAFE_FWRITE_TO_STDERR( \
|
||||
"[rclcpp|logging.hpp] RCLCPP_@(severity)@(suffix) could not get current time stamp\n"); \
|
||||
return RCUTILS_RET_ERROR; \
|
||||
} \
|
||||
return RCUTILS_RET_OK; \
|
||||
}; \
|
||||
@[ end if] \
|
||||
@[ if 'stream' in feature_combination]@
|
||||
std::stringstream rclcpp_stream_ss_; \
|
||||
rclcpp_stream_ss_ << @(stream_arg); \
|
||||
@[ end if]@
|
||||
RCUTILS_LOG_@(severity)@(get_suffix_from_features(feature_combination))_NAMED( \
|
||||
@{params = ['get_time_point' if p == 'clock' and 'throttle' in feature_combination else p for p in params]}@
|
||||
@[ if params]@
|
||||
@(''.join([' ' + p + ', \\\n' for p in params if p != stream_arg]))@
|
||||
@[ end if]@
|
||||
(logger).get_name(), \
|
||||
@[ if 'stream' not in feature_combination]@
|
||||
__VA_ARGS__); \
|
||||
@[ else]@
|
||||
"%s", rclcpp_stream_ss_.str().c_str()); \
|
||||
@[ end if]@
|
||||
} while (0)
|
||||
|
||||
@[ end for]@
|
||||
#endif
|
||||
///@@}
|
||||
|
||||
@[end for]@
|
||||
|
||||
#endif // RCLCPP__LOGGING_HPP_
|
||||
@@ -83,6 +83,16 @@ Clock::now() const
|
||||
return now;
|
||||
}
|
||||
|
||||
void
|
||||
Clock::cancel_sleep_or_wait()
|
||||
{
|
||||
{
|
||||
std::unique_lock lock(impl_->wait_mutex_);
|
||||
impl_->stop_sleeping_ = true;
|
||||
}
|
||||
impl_->cv_.notify_one();
|
||||
}
|
||||
|
||||
bool
|
||||
Clock::sleep_until(
|
||||
Time until,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "rclcpp/context.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
@@ -28,7 +29,7 @@
|
||||
#include "rclcpp/detail/utilities.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/graph_listener.hpp"
|
||||
|
||||
#include "rcutils/error_handling.h"
|
||||
#include "rcutils/macros.h"
|
||||
|
||||
@@ -142,12 +143,52 @@ rclcpp_logging_output_handler(
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
/**
|
||||
* Global storage for pre and post shutdown recursive mutexes.
|
||||
* Note, this is a ABI compatibility hack.
|
||||
*/
|
||||
class MutexLookup
|
||||
{
|
||||
std::mutex m;
|
||||
|
||||
struct MutexHolder
|
||||
{
|
||||
std::recursive_mutex on_shutdown_callbacks_mutex_;
|
||||
std::recursive_mutex pre_shutdown_callbacks_mutex_;
|
||||
};
|
||||
|
||||
std::map<const Context *, std::unique_ptr<MutexHolder>> mutexMap;
|
||||
|
||||
public:
|
||||
MutexHolder & getMutexes(const Context *forContext)
|
||||
{
|
||||
auto it = mutexMap.find(forContext);
|
||||
if(it == mutexMap.end()) {
|
||||
it = mutexMap.emplace(forContext, std::make_unique<MutexHolder>()).first;
|
||||
}
|
||||
|
||||
return *(it->second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Only supposed to be called on deletion of context
|
||||
*/
|
||||
void removeMutexes(const Context *forContext)
|
||||
{
|
||||
mutexMap.erase(forContext);
|
||||
}
|
||||
};
|
||||
|
||||
MutexLookup mutexStorage;
|
||||
|
||||
Context::Context()
|
||||
: rcl_context_(nullptr),
|
||||
shutdown_reason_(""),
|
||||
logging_mutex_(nullptr),
|
||||
graph_listener_(nullptr)
|
||||
{}
|
||||
logging_mutex_(nullptr)
|
||||
{
|
||||
// allocate mutexes
|
||||
mutexStorage.getMutexes(this);
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
@@ -166,6 +207,9 @@ Context::~Context()
|
||||
} catch (...) {
|
||||
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "unhandled exception in ~Context()");
|
||||
}
|
||||
|
||||
// delete mutexes
|
||||
mutexStorage.removeMutexes(this);
|
||||
}
|
||||
|
||||
RCLCPP_LOCAL
|
||||
@@ -244,24 +288,6 @@ Context::init(
|
||||
|
||||
weak_contexts_ = get_weak_contexts();
|
||||
weak_contexts_->add_context(this->shared_from_this());
|
||||
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock (on_shutdown_callbacks_mutex_);
|
||||
|
||||
graph_listener_ = std::make_shared<graph_listener::GraphListener>(shared_from_this());
|
||||
|
||||
if (!graph_listener_->is_started()) {
|
||||
// Register an on_shutdown hook to shutdown the graph listener.
|
||||
// This is important to ensure that the wait set is finalized before
|
||||
// destruction of static objects occurs.
|
||||
std::weak_ptr<rclcpp::graph_listener::GraphListener> weak_graph_listener = graph_listener_;
|
||||
on_shutdown ([weak_graph_listener]() {
|
||||
auto shared_graph_listener = weak_graph_listener.lock();
|
||||
if(shared_graph_listener) {
|
||||
shared_graph_listener->shutdown(std::nothrow);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (const std::exception & e) {
|
||||
ret = rcl_shutdown(rcl_context_.get());
|
||||
rcl_context_.reset();
|
||||
@@ -329,7 +355,8 @@ Context::shutdown(const std::string & reason)
|
||||
|
||||
// call each pre-shutdown callback
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock{pre_shutdown_callbacks_mutex_};
|
||||
std::lock_guard<std::recursive_mutex> lock{mutexStorage.getMutexes(
|
||||
this).pre_shutdown_callbacks_mutex_};
|
||||
// callbacks may delete other callbacks during the execution,
|
||||
// therefore we need to save a copy and check before execution
|
||||
// if the next callback is still present
|
||||
@@ -351,7 +378,8 @@ Context::shutdown(const std::string & reason)
|
||||
shutdown_reason_ = reason;
|
||||
// call each shutdown callback
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
|
||||
this).on_shutdown_callbacks_mutex_);
|
||||
// callbacks may delete other callbacks during the execution,
|
||||
// therefore we need to save a copy and check before execution
|
||||
// if the next callback is still present
|
||||
@@ -431,10 +459,12 @@ Context::add_shutdown_callback(
|
||||
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||
|
||||
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||
std::lock_guard<std::recursive_mutex> lock(pre_shutdown_callbacks_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
|
||||
this).pre_shutdown_callbacks_mutex_);
|
||||
pre_shutdown_callbacks_.emplace_back(callback_shared_ptr);
|
||||
} else {
|
||||
std::lock_guard<std::recursive_mutex> lock(on_shutdown_callbacks_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutexStorage.getMutexes(
|
||||
this).on_shutdown_callbacks_mutex_);
|
||||
on_shutdown_callbacks_.emplace_back(callback_shared_ptr);
|
||||
}
|
||||
|
||||
@@ -465,6 +495,7 @@ Context::remove_shutdown_callback(
|
||||
return false;
|
||||
}
|
||||
callback_vector.erase(iter);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -472,9 +503,11 @@ Context::remove_shutdown_callback(
|
||||
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_);
|
||||
return remove_callback(mutexStorage.getMutexes(this).pre_shutdown_callbacks_mutex_,
|
||||
pre_shutdown_callbacks_);
|
||||
} else {
|
||||
return remove_callback(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
|
||||
return remove_callback(mutexStorage.getMutexes(this).on_shutdown_callbacks_mutex_,
|
||||
on_shutdown_callbacks_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,9 +540,11 @@ Context::get_shutdown_callback() const
|
||||
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||
|
||||
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||
return get_callback_vector(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
|
||||
return get_callback_vector(mutexStorage.getMutexes(this).pre_shutdown_callbacks_mutex_,
|
||||
pre_shutdown_callbacks_);
|
||||
} else {
|
||||
return get_callback_vector(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
|
||||
return get_callback_vector(mutexStorage.getMutexes(this).on_shutdown_callbacks_mutex_,
|
||||
on_shutdown_callbacks_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -519,12 +554,6 @@ Context::get_rcl_context()
|
||||
return rcl_context_;
|
||||
}
|
||||
|
||||
std::shared_ptr<rclcpp::graph_listener::GraphListener>
|
||||
Context::get_graph_listener()
|
||||
{
|
||||
return graph_listener_;
|
||||
}
|
||||
|
||||
bool
|
||||
Context::sleep_for(const std::chrono::nanoseconds & nanoseconds)
|
||||
{
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -53,7 +52,6 @@ class rclcpp::ExecutorImplementation {};
|
||||
|
||||
Executor::Executor(const std::shared_ptr<rclcpp::Context> & context)
|
||||
: spinning(false),
|
||||
context_(context),
|
||||
entities_need_rebuild_(true),
|
||||
collector_(nullptr),
|
||||
wait_set_({}, {}, {}, {}, {}, {}, context)
|
||||
@@ -188,11 +186,6 @@ Executor::add_callback_group(
|
||||
void
|
||||
Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
|
||||
{
|
||||
if (node_ptr->get_context() != context_) {
|
||||
throw std::runtime_error(
|
||||
"add_node() called with a node with a different context from this executor");
|
||||
}
|
||||
|
||||
this->collector_.add_node(node_ptr);
|
||||
|
||||
try {
|
||||
@@ -640,7 +633,7 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
|
||||
throw std::runtime_error("Unimplemented");
|
||||
}
|
||||
|
||||
case rclcpp::DeliveredMessageKind::INVALID:
|
||||
default:
|
||||
{
|
||||
throw std::runtime_error("Delivered message kind is not supported");
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/executors.hpp"
|
||||
#include "rcpputils/compile_warnings.hpp"
|
||||
|
||||
void
|
||||
rclcpp::spin_all(
|
||||
@@ -26,6 +25,12 @@ rclcpp::spin_all(
|
||||
exec.spin_node_all(node_ptr, max_duration);
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
rclcpp::spin_all(node_ptr->get_node_base_interface(), max_duration);
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
|
||||
{
|
||||
@@ -35,6 +40,12 @@ rclcpp::spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr
|
||||
exec.spin_node_some(node_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin_some(rclcpp::Node::SharedPtr node_ptr)
|
||||
{
|
||||
rclcpp::spin_some(node_ptr->get_node_base_interface());
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
|
||||
{
|
||||
@@ -51,19 +62,3 @@ rclcpp::spin(rclcpp::Node::SharedPtr node_ptr)
|
||||
{
|
||||
rclcpp::spin(node_ptr->get_node_base_interface());
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin_all(rclcpp::Node::SharedPtr node_ptr, std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_START
|
||||
rclcpp::spin_all(node_ptr->get_node_base_interface(), max_duration);
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin_some(rclcpp::Node::SharedPtr node_ptr)
|
||||
{
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_START
|
||||
rclcpp::spin_some(node_ptr->get_node_base_interface());
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
|
||||
}
|
||||
|
||||
223
rclcpp/src/rclcpp/executors/static_single_threaded_executor.cpp
Normal file
223
rclcpp/src/rclcpp/executors/static_single_threaded_executor.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
// Copyright 2019 Nobleo Technology
|
||||
//
|
||||
// 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/executors/executor_entities_collection.hpp"
|
||||
#include "rcpputils/scope_exit.hpp"
|
||||
|
||||
#include "rclcpp/executors/static_single_threaded_executor.hpp"
|
||||
#include "rclcpp/any_executable.hpp"
|
||||
|
||||
using rclcpp::executors::StaticSingleThreadedExecutor;
|
||||
|
||||
StaticSingleThreadedExecutor::StaticSingleThreadedExecutor(const rclcpp::ExecutorOptions & options)
|
||||
: rclcpp::Executor(options)
|
||||
{
|
||||
}
|
||||
|
||||
StaticSingleThreadedExecutor::~StaticSingleThreadedExecutor() {}
|
||||
|
||||
void
|
||||
StaticSingleThreadedExecutor::spin()
|
||||
{
|
||||
if (spinning.exchange(true)) {
|
||||
throw std::runtime_error("spin() called while already spinning");
|
||||
}
|
||||
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false); );
|
||||
|
||||
// This is essentially the contents of the rclcpp::Executor::wait_for_work method,
|
||||
// except we need to keep the wait result to reproduce the StaticSingleThreadedExecutor
|
||||
// behavior.
|
||||
while (rclcpp::ok(this->context_) && spinning.load()) {
|
||||
this->spin_once_impl(std::chrono::nanoseconds(-1));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StaticSingleThreadedExecutor::spin_some(std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
// In this context a 0 input max_duration means no duration limit
|
||||
if (std::chrono::nanoseconds(0) == max_duration) {
|
||||
max_duration = std::chrono::nanoseconds::max();
|
||||
}
|
||||
return this->spin_some_impl(max_duration, false);
|
||||
}
|
||||
|
||||
void
|
||||
StaticSingleThreadedExecutor::spin_all(std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
if (max_duration < std::chrono::nanoseconds(0)) {
|
||||
throw std::invalid_argument("max_duration must be greater than or equal to 0");
|
||||
}
|
||||
return this->spin_some_impl(max_duration, true);
|
||||
}
|
||||
|
||||
void
|
||||
StaticSingleThreadedExecutor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
|
||||
{
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto max_duration_not_elapsed = [max_duration, start]() {
|
||||
const auto spin_forever = std::chrono::nanoseconds(0) == max_duration;
|
||||
const auto cur_duration = std::chrono::steady_clock::now() - start;
|
||||
return spin_forever || (cur_duration < max_duration);
|
||||
};
|
||||
|
||||
if (spinning.exchange(true)) {
|
||||
throw std::runtime_error("spin_some() called while already spinning");
|
||||
}
|
||||
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false););
|
||||
|
||||
while (rclcpp::ok(context_) && spinning.load() && max_duration_not_elapsed()) {
|
||||
// Get executables that are ready now
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
|
||||
auto wait_result = this->collect_and_wait(std::chrono::nanoseconds(0));
|
||||
if (wait_result.has_value()) {
|
||||
// Execute ready executables
|
||||
bool work_available = this->execute_ready_executables(
|
||||
current_collection_,
|
||||
wait_result.value(),
|
||||
false);
|
||||
if (!work_available || !exhaustive) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StaticSingleThreadedExecutor::spin_once_impl(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
if (rclcpp::ok(context_) && spinning.load()) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
auto wait_result = this->collect_and_wait(timeout);
|
||||
if (wait_result.has_value()) {
|
||||
this->execute_ready_executables(current_collection_, wait_result.value(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<rclcpp::WaitResult<rclcpp::WaitSet>>
|
||||
StaticSingleThreadedExecutor::collect_and_wait(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
// we need to make sure that callback groups don't get out of scope
|
||||
// during the wait. As in jazzy, they are not covered by the DynamicStorage,
|
||||
// we explicitly hold them here as a bugfix
|
||||
std::vector<rclcpp::CallbackGroup::SharedPtr> cbgs;
|
||||
|
||||
if (this->entities_need_rebuild_.exchange(false) || current_collection_.empty()) {
|
||||
this->collect_entities();
|
||||
}
|
||||
|
||||
auto callback_groups = this->collector_.get_all_callback_groups();
|
||||
cbgs.resize(callback_groups.size());
|
||||
for(const auto & w_ptr : callback_groups) {
|
||||
auto shr_ptr = w_ptr.lock();
|
||||
if(shr_ptr) {
|
||||
cbgs.push_back(std::move(shr_ptr));
|
||||
}
|
||||
}
|
||||
|
||||
auto wait_result = wait_set_.wait(std::chrono::nanoseconds(timeout));
|
||||
|
||||
// drop references to the callback groups, before trying to execute anything
|
||||
cbgs.clear();
|
||||
|
||||
if (wait_result.kind() == WaitResultKind::Empty) {
|
||||
RCUTILS_LOG_WARN_NAMED(
|
||||
"rclcpp",
|
||||
"empty wait set received in wait(). This should never happen.");
|
||||
return {};
|
||||
} else {
|
||||
if (wait_result.kind() == WaitResultKind::Ready && current_notify_waitable_) {
|
||||
auto & rcl_wait_set = wait_result.get_wait_set().get_rcl_wait_set();
|
||||
if (current_notify_waitable_->is_ready(rcl_wait_set)) {
|
||||
current_notify_waitable_->execute(current_notify_waitable_->take_data());
|
||||
}
|
||||
}
|
||||
}
|
||||
return wait_result;
|
||||
}
|
||||
|
||||
// This preserves the "scheduling semantics" of the StaticSingleThreadedExecutor
|
||||
// from the original implementation.
|
||||
bool StaticSingleThreadedExecutor::execute_ready_executables(
|
||||
const rclcpp::executors::ExecutorEntitiesCollection & collection,
|
||||
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result,
|
||||
bool spin_once)
|
||||
{
|
||||
bool any_ready_executable = false;
|
||||
if (wait_result.kind() != rclcpp::WaitResultKind::Ready) {
|
||||
return any_ready_executable;
|
||||
}
|
||||
|
||||
while (auto subscription = wait_result.next_ready_subscription()) {
|
||||
auto entity_iter = collection.subscriptions.find(subscription->get_subscription_handle().get());
|
||||
if (entity_iter != collection.subscriptions.end()) {
|
||||
execute_subscription(subscription);
|
||||
any_ready_executable = true;
|
||||
if (spin_once) {return any_ready_executable;}
|
||||
}
|
||||
}
|
||||
|
||||
size_t current_timer_index = 0;
|
||||
while (true) {
|
||||
auto [timer, timer_index] = wait_result.peek_next_ready_timer(current_timer_index);
|
||||
if (nullptr == timer) {
|
||||
break;
|
||||
}
|
||||
current_timer_index = timer_index;
|
||||
auto entity_iter = collection.timers.find(timer->get_timer_handle().get());
|
||||
if (entity_iter != collection.timers.end()) {
|
||||
wait_result.clear_timer_with_index(current_timer_index);
|
||||
auto data = timer->call();
|
||||
if (!data) {
|
||||
// someone canceled the timer between is_ready and call
|
||||
continue;
|
||||
}
|
||||
|
||||
execute_timer(std::move(timer), data);
|
||||
any_ready_executable = true;
|
||||
if (spin_once) {return any_ready_executable;}
|
||||
}
|
||||
}
|
||||
|
||||
while (auto client = wait_result.next_ready_client()) {
|
||||
auto entity_iter = collection.clients.find(client->get_client_handle().get());
|
||||
if (entity_iter != collection.clients.end()) {
|
||||
execute_client(client);
|
||||
any_ready_executable = true;
|
||||
if (spin_once) {return any_ready_executable;}
|
||||
}
|
||||
}
|
||||
|
||||
while (auto service = wait_result.next_ready_service()) {
|
||||
auto entity_iter = collection.services.find(service->get_service_handle().get());
|
||||
if (entity_iter != collection.services.end()) {
|
||||
execute_service(service);
|
||||
any_ready_executable = true;
|
||||
if (spin_once) {return any_ready_executable;}
|
||||
}
|
||||
}
|
||||
|
||||
while (auto waitable = wait_result.next_ready_waitable()) {
|
||||
auto entity_iter = collection.waitables.find(waitable.get());
|
||||
if (entity_iter != collection.waitables.end()) {
|
||||
const auto data = waitable->take_data();
|
||||
waitable->execute(data);
|
||||
any_ready_executable = true;
|
||||
if (spin_once) {return any_ready_executable;}
|
||||
}
|
||||
}
|
||||
return any_ready_executable;
|
||||
}
|
||||
@@ -25,9 +25,9 @@ using namespace std::chrono_literals;
|
||||
using rclcpp::experimental::executors::EventsExecutor;
|
||||
|
||||
EventsExecutor::EventsExecutor(
|
||||
const rclcpp::ExecutorOptions & options,
|
||||
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue,
|
||||
bool execute_timers_separate_thread)
|
||||
bool execute_timers_separate_thread,
|
||||
const rclcpp::ExecutorOptions & options)
|
||||
: rclcpp::Executor(options)
|
||||
{
|
||||
// Get ownership of the queue used to store events.
|
||||
|
||||
@@ -37,30 +37,6 @@ GenericSubscription::create_serialized_message()
|
||||
return std::make_shared<rclcpp::SerializedMessage>(0);
|
||||
}
|
||||
|
||||
void
|
||||
GenericSubscription::disable_callbacks()
|
||||
{
|
||||
SubscriptionBase::disable_callbacks();
|
||||
any_callback_.disable();
|
||||
for (const auto & [_, event_ptr] : event_handlers_) {
|
||||
if (event_ptr) {
|
||||
event_ptr->disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericSubscription::enable_callbacks()
|
||||
{
|
||||
SubscriptionBase::enable_callbacks();
|
||||
any_callback_.enable();
|
||||
for (const auto & [_, event_ptr] : event_handlers_) {
|
||||
if (event_ptr) {
|
||||
event_ptr->enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericSubscription::handle_message(
|
||||
std::shared_ptr<void> &,
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/types.h"
|
||||
#include "rclcpp/detail/add_guard_condition_to_rcl_wait_set.hpp"
|
||||
@@ -37,7 +38,8 @@ namespace graph_listener
|
||||
{
|
||||
|
||||
GraphListener::GraphListener(const std::shared_ptr<Context> & parent_context)
|
||||
: rcl_parent_context_(parent_context->get_rcl_context()),
|
||||
: weak_parent_context_(parent_context),
|
||||
rcl_parent_context_(parent_context->get_rcl_context()),
|
||||
is_started_(false),
|
||||
is_shutdown_(false),
|
||||
interrupt_guard_condition_(parent_context)
|
||||
@@ -70,11 +72,23 @@ void
|
||||
GraphListener::start_if_not_started()
|
||||
{
|
||||
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
|
||||
if (is_shutdown()) {
|
||||
if (is_shutdown_.load()) {
|
||||
throw GraphListenerShutdownError();
|
||||
}
|
||||
|
||||
if (!is_started()) {
|
||||
auto parent_context = weak_parent_context_.lock();
|
||||
if (!is_started_ && parent_context) {
|
||||
// Register an on_shutdown hook to shtudown the graph listener.
|
||||
// This is important to ensure that the wait set is finalized before
|
||||
// destruction of static objects occurs.
|
||||
std::weak_ptr<GraphListener> weak_this = shared_from_this();
|
||||
parent_context->on_shutdown(
|
||||
[weak_this]() {
|
||||
auto shared_this = weak_this.lock();
|
||||
if (shared_this) {
|
||||
// should not throw from on_shutdown if it can be avoided
|
||||
shared_this->shutdown(std::nothrow);
|
||||
}
|
||||
});
|
||||
// Initialize the wait set before starting.
|
||||
init_wait_set();
|
||||
// Start the listener thread.
|
||||
@@ -108,7 +122,7 @@ GraphListener::run_loop()
|
||||
{
|
||||
while (true) {
|
||||
// If shutdown() was called, exit.
|
||||
if (is_shutdown()) {
|
||||
if (is_shutdown_.load()) {
|
||||
return;
|
||||
}
|
||||
rcl_ret_t ret;
|
||||
@@ -176,7 +190,7 @@ GraphListener::run_loop()
|
||||
if (graph_gc == wait_set_.guard_conditions[graph_gc_indexes[i]]) {
|
||||
node_ptr->notify_graph_change();
|
||||
}
|
||||
if (is_shutdown()) {
|
||||
if (is_shutdown_) {
|
||||
// If shutdown, then notify the node of this as well.
|
||||
node_ptr->notify_shutdown();
|
||||
}
|
||||
@@ -243,7 +257,7 @@ GraphListener::add_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph
|
||||
throw std::invalid_argument("node is nullptr");
|
||||
}
|
||||
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
|
||||
if (is_shutdown()) {
|
||||
if (is_shutdown_.load()) {
|
||||
throw GraphListenerShutdownError();
|
||||
}
|
||||
|
||||
@@ -318,11 +332,11 @@ GraphListener::__shutdown()
|
||||
{
|
||||
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
|
||||
if (!is_shutdown_.exchange(true)) {
|
||||
if (is_started()) {
|
||||
if (is_started_) {
|
||||
interrupt_(&interrupt_guard_condition_);
|
||||
listener_thread_.join();
|
||||
}
|
||||
if (is_started()) {
|
||||
if (is_started_) {
|
||||
cleanup_wait_set();
|
||||
}
|
||||
}
|
||||
@@ -351,12 +365,6 @@ GraphListener::shutdown(const std::nothrow_t &) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
GraphListener::is_started()
|
||||
{
|
||||
return is_started_;
|
||||
}
|
||||
|
||||
bool
|
||||
GraphListener::is_shutdown()
|
||||
{
|
||||
|
||||
@@ -55,6 +55,34 @@ get_node_logger(const rcl_node_t * node)
|
||||
return rclcpp::get_logger(logger_name);
|
||||
}
|
||||
|
||||
// TODO(ahcorde): Remove deprecated class on the next release (in Rolling after Kilted).
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
rcpputils::fs::path
|
||||
get_logging_directory()
|
||||
{
|
||||
char * log_dir = NULL;
|
||||
auto allocator = rcutils_get_default_allocator();
|
||||
rcl_logging_ret_t ret = rcl_logging_get_logging_directory(allocator, &log_dir);
|
||||
if (RCL_LOGGING_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||
}
|
||||
std::string path{log_dir};
|
||||
allocator.deallocate(log_dir, allocator.state);
|
||||
return path;
|
||||
}
|
||||
// remove warning suppression
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
std::filesystem::path
|
||||
get_log_directory()
|
||||
{
|
||||
|
||||
@@ -547,18 +547,6 @@ Node::get_subscriptions_info_by_topic(const std::string & topic_name, bool no_ma
|
||||
return node_graph_->get_subscriptions_info_by_topic(topic_name, no_mangle);
|
||||
}
|
||||
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
Node::get_clients_info_by_service(const std::string & service_name, bool no_mangle) const
|
||||
{
|
||||
return node_graph_->get_clients_info_by_service(service_name, no_mangle);
|
||||
}
|
||||
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
Node::get_servers_info_by_service(const std::string & service_name, bool no_mangle) const
|
||||
{
|
||||
return node_graph_->get_servers_info_by_service(service_name, no_mangle);
|
||||
}
|
||||
|
||||
void
|
||||
Node::for_each_callback_group(
|
||||
const node_interfaces::NodeBaseInterface::CallbackGroupFunction & func)
|
||||
|
||||
@@ -275,6 +275,16 @@ NodeBase::get_associated_with_executor_atomic()
|
||||
return associated_with_executor_;
|
||||
}
|
||||
|
||||
rclcpp::GuardCondition &
|
||||
NodeBase::get_notify_guard_condition()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> notify_condition_lock(notify_guard_condition_mutex_);
|
||||
if (!notify_guard_condition_is_valid_) {
|
||||
throw std::runtime_error("failed to get notify guard condition because it is invalid");
|
||||
}
|
||||
return *notify_guard_condition_;
|
||||
}
|
||||
|
||||
rclcpp::GuardCondition::SharedPtr
|
||||
NodeBase::get_shared_notify_guard_condition()
|
||||
{
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "rclcpp/node_interfaces/node_graph.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
@@ -37,6 +36,9 @@ using rclcpp::graph_listener::GraphListener;
|
||||
|
||||
NodeGraph::NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base)
|
||||
: node_base_(node_base),
|
||||
graph_listener_(
|
||||
node_base->get_context()->get_sub_context<GraphListener>(node_base->get_context())
|
||||
),
|
||||
should_add_to_graph_listener_(true),
|
||||
graph_users_count_(0)
|
||||
{}
|
||||
@@ -48,7 +50,7 @@ NodeGraph::~NodeGraph()
|
||||
// graph listener after checking that it was not here.
|
||||
if (!should_add_to_graph_listener_.exchange(false)) {
|
||||
// If it was already false, then it needs to now be removed.
|
||||
node_base_->get_context()->get_graph_listener()->remove_node(this);
|
||||
graph_listener_->remove_node(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,7 +419,7 @@ NodeGraph::get_node_names_and_namespaces() const
|
||||
rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error_msg.c_str());
|
||||
// TODO(karsten1987): Append rcutils_error_message once it's in master
|
||||
throw std::runtime_error(error_msg);
|
||||
}
|
||||
|
||||
@@ -432,15 +434,20 @@ NodeGraph::get_node_names_and_namespaces() const
|
||||
std::string error;
|
||||
rcl_ret_t ret_names = rcutils_string_array_fini(&node_names_c);
|
||||
if (ret_names != RCUTILS_RET_OK) {
|
||||
error = std::string("could not destroy node names: ") + rcl_get_error_string().str;
|
||||
// *INDENT-OFF*
|
||||
// TODO(karsten1987): Append rcutils_error_message once it's in master
|
||||
error = "could not destroy node names";
|
||||
// *INDENT-ON*
|
||||
}
|
||||
rcl_ret_t ret_ns = rcutils_string_array_fini(&node_namespaces_c);
|
||||
if (ret_ns != RCUTILS_RET_OK) {
|
||||
error += std::string(", could not destroy node namespaces: ") + rcl_get_error_string().str;
|
||||
// *INDENT-OFF*
|
||||
// TODO(karsten1987): Append rcutils_error_message once it's in master
|
||||
error += ", could not destroy node namespaces";
|
||||
// *INDENT-ON*
|
||||
}
|
||||
|
||||
if (ret_names != RCUTILS_RET_OK || ret_ns != RCUTILS_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED("rclcpp", "%s", error.c_str());
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
@@ -596,8 +603,8 @@ NodeGraph::get_graph_event()
|
||||
}
|
||||
// on first call, add node to graph_listener_
|
||||
if (should_add_to_graph_listener_.exchange(false)) {
|
||||
node_base_->get_context()->get_graph_listener()->add_node(this);
|
||||
node_base_->get_context()->get_graph_listener()->start_if_not_started();
|
||||
graph_listener_->add_node(this);
|
||||
graph_listener_->start_if_not_started();
|
||||
}
|
||||
return event;
|
||||
}
|
||||
@@ -754,122 +761,6 @@ NodeGraph::get_subscriptions_info_by_topic(
|
||||
rcl_get_subscriptions_info_by_topic);
|
||||
}
|
||||
|
||||
static
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
convert_to_service_info_list(const rcl_service_endpoint_info_array_t & info_array)
|
||||
{
|
||||
std::vector<rclcpp::ServiceEndpointInfo> service_info_list;
|
||||
for (size_t i = 0; i < info_array.size; ++i) {
|
||||
service_info_list.push_back(rclcpp::ServiceEndpointInfo(info_array.info_array[i]));
|
||||
}
|
||||
return service_info_list;
|
||||
}
|
||||
|
||||
template<const char * EndpointType, typename FunctionT>
|
||||
static std::vector<rclcpp::ServiceEndpointInfo>
|
||||
get_info_by_service(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & service_name,
|
||||
bool no_mangle,
|
||||
FunctionT rcl_get_info_by_service)
|
||||
{
|
||||
std::string fqdn;
|
||||
auto rcl_node_handle = node_base->get_rcl_node_handle();
|
||||
|
||||
if (no_mangle) {
|
||||
fqdn = service_name;
|
||||
} else {
|
||||
fqdn = rclcpp::expand_topic_or_service_name(
|
||||
service_name,
|
||||
rcl_node_get_name(rcl_node_handle),
|
||||
rcl_node_get_namespace(rcl_node_handle),
|
||||
true);
|
||||
|
||||
// Get the node options
|
||||
const rcl_node_options_t * node_options = rcl_node_get_options(rcl_node_handle);
|
||||
if (nullptr == node_options) {
|
||||
throw std::runtime_error("Need valid node options in get_info_by_service()");
|
||||
}
|
||||
const rcl_arguments_t * global_args = nullptr;
|
||||
if (node_options->use_global_arguments) {
|
||||
global_args = &(rcl_node_handle->context->global_arguments);
|
||||
}
|
||||
|
||||
char * remapped_service_name = nullptr;
|
||||
rcl_ret_t ret = rcl_remap_service_name(
|
||||
&(node_options->arguments),
|
||||
global_args,
|
||||
fqdn.c_str(),
|
||||
rcl_node_get_name(rcl_node_handle),
|
||||
rcl_node_get_namespace(rcl_node_handle),
|
||||
node_options->allocator,
|
||||
&remapped_service_name);
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw_from_rcl_error(ret, std::string("Failed to remap service name ") + fqdn);
|
||||
} else if (nullptr != remapped_service_name) {
|
||||
fqdn = remapped_service_name;
|
||||
node_options->allocator.deallocate(remapped_service_name, node_options->allocator.state);
|
||||
}
|
||||
}
|
||||
|
||||
rcutils_allocator_t allocator = rcutils_get_default_allocator();
|
||||
rcl_service_endpoint_info_array_t info_array =
|
||||
rcl_get_zero_initialized_service_endpoint_info_array();
|
||||
rcl_ret_t ret =
|
||||
rcl_get_info_by_service(rcl_node_handle, &allocator, fqdn.c_str(), no_mangle, &info_array);
|
||||
if (RCL_RET_OK != ret) {
|
||||
auto error_msg =
|
||||
std::string("Failed to get information by service for ") + EndpointType + std::string(":");
|
||||
if (RCL_RET_UNSUPPORTED == ret) {
|
||||
error_msg += std::string("function not supported by RMW_IMPLEMENTATION");
|
||||
} else {
|
||||
error_msg += rcl_get_error_string().str;
|
||||
}
|
||||
rcl_reset_error();
|
||||
if (RCL_RET_OK != rcl_service_endpoint_info_array_fini(&info_array, &allocator)) {
|
||||
error_msg += std::string(", failed also to cleanup service info array, leaking memory: ") +
|
||||
rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
}
|
||||
throw_from_rcl_error(ret, error_msg);
|
||||
}
|
||||
|
||||
std::vector<rclcpp::ServiceEndpointInfo> service_info_list =
|
||||
convert_to_service_info_list(info_array);
|
||||
ret = rcl_service_endpoint_info_array_fini(&info_array, &allocator);
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw_from_rcl_error(ret, "rcl_service_info_array_fini failed.");
|
||||
}
|
||||
|
||||
return service_info_list;
|
||||
}
|
||||
|
||||
static constexpr char kClientEndpointTypeName[] = "clients";
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
NodeGraph::get_clients_info_by_service(
|
||||
const std::string & service_name,
|
||||
bool no_mangle) const
|
||||
{
|
||||
return get_info_by_service<kClientEndpointTypeName>(
|
||||
node_base_,
|
||||
service_name,
|
||||
no_mangle,
|
||||
rcl_get_clients_info_by_service);
|
||||
}
|
||||
|
||||
static constexpr char kServerEndpointTypeName[] = "servers";
|
||||
std::vector<rclcpp::ServiceEndpointInfo>
|
||||
NodeGraph::get_servers_info_by_service(
|
||||
const std::string & service_name,
|
||||
bool no_mangle) const
|
||||
{
|
||||
return get_info_by_service<kServerEndpointTypeName>(
|
||||
node_base_,
|
||||
service_name,
|
||||
no_mangle,
|
||||
rcl_get_servers_info_by_service);
|
||||
}
|
||||
|
||||
std::string &
|
||||
rclcpp::TopicEndpointInfo::node_name()
|
||||
{
|
||||
@@ -953,99 +844,3 @@ rclcpp::TopicEndpointInfo::topic_type_hash() const
|
||||
{
|
||||
return topic_type_hash_;
|
||||
}
|
||||
|
||||
std::string &
|
||||
rclcpp::ServiceEndpointInfo::node_name()
|
||||
{
|
||||
return node_name_;
|
||||
}
|
||||
|
||||
const std::string &
|
||||
rclcpp::ServiceEndpointInfo::node_name() const
|
||||
{
|
||||
return node_name_;
|
||||
}
|
||||
|
||||
std::string &
|
||||
rclcpp::ServiceEndpointInfo::node_namespace()
|
||||
{
|
||||
return node_namespace_;
|
||||
}
|
||||
|
||||
const std::string &
|
||||
rclcpp::ServiceEndpointInfo::node_namespace() const
|
||||
{
|
||||
return node_namespace_;
|
||||
}
|
||||
|
||||
std::string &
|
||||
rclcpp::ServiceEndpointInfo::service_type()
|
||||
{
|
||||
return service_type_;
|
||||
}
|
||||
|
||||
const std::string &
|
||||
rclcpp::ServiceEndpointInfo::service_type() const
|
||||
{
|
||||
return service_type_;
|
||||
}
|
||||
|
||||
rclcpp::EndpointType &
|
||||
rclcpp::ServiceEndpointInfo::endpoint_type()
|
||||
{
|
||||
return endpoint_type_;
|
||||
}
|
||||
|
||||
const rclcpp::EndpointType &
|
||||
rclcpp::ServiceEndpointInfo::endpoint_type() const
|
||||
{
|
||||
return endpoint_type_;
|
||||
}
|
||||
|
||||
size_t &
|
||||
rclcpp::ServiceEndpointInfo::endpoint_count()
|
||||
{
|
||||
return endpoint_count_;
|
||||
}
|
||||
|
||||
const size_t &
|
||||
rclcpp::ServiceEndpointInfo::endpoint_count() const
|
||||
{
|
||||
return endpoint_count_;
|
||||
}
|
||||
|
||||
std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
|
||||
rclcpp::ServiceEndpointInfo::endpoint_gids()
|
||||
{
|
||||
return endpoint_gids_;
|
||||
}
|
||||
|
||||
const std::vector<std::array<uint8_t, RMW_GID_STORAGE_SIZE>> &
|
||||
rclcpp::ServiceEndpointInfo::endpoint_gids() const
|
||||
{
|
||||
return endpoint_gids_;
|
||||
}
|
||||
|
||||
std::vector<rclcpp::QoS> &
|
||||
rclcpp::ServiceEndpointInfo::qos_profiles()
|
||||
{
|
||||
return qos_profiles_;
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::QoS> &
|
||||
rclcpp::ServiceEndpointInfo::qos_profiles() const
|
||||
{
|
||||
return qos_profiles_;
|
||||
}
|
||||
|
||||
rosidl_type_hash_t &
|
||||
rclcpp::ServiceEndpointInfo::service_type_hash()
|
||||
{
|
||||
return service_type_hash_;
|
||||
}
|
||||
|
||||
const rosidl_type_hash_t &
|
||||
rclcpp::ServiceEndpointInfo::service_type_hash() const
|
||||
{
|
||||
return service_type_hash_;
|
||||
}
|
||||
|
||||
@@ -192,65 +192,6 @@ format_range_reason(const std::string & name, const char * range_type)
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
RCLCPP_LOCAL
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
__check_integer_range(
|
||||
const rcl_interfaces::msg::ParameterDescriptor & descriptor,
|
||||
const int64_t value)
|
||||
{
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
auto integer_range = descriptor.integer_range.at(0);
|
||||
if (value == integer_range.from_value || value == integer_range.to_value) {
|
||||
return result;
|
||||
}
|
||||
if ((value < integer_range.from_value) || (value > integer_range.to_value)) {
|
||||
result.successful = false;
|
||||
result.reason = format_range_reason(descriptor.name, "integer");
|
||||
return result;
|
||||
}
|
||||
if (integer_range.step == 0) {
|
||||
return result;
|
||||
}
|
||||
if (((value - integer_range.from_value) % integer_range.step) == 0) {
|
||||
return result;
|
||||
}
|
||||
result.successful = false;
|
||||
result.reason = format_range_reason(descriptor.name, "integer");
|
||||
return result;
|
||||
}
|
||||
|
||||
RCLCPP_LOCAL
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
__check_double_range(
|
||||
const rcl_interfaces::msg::ParameterDescriptor & descriptor,
|
||||
const double value)
|
||||
{
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
auto fp_range = descriptor.floating_point_range.at(0);
|
||||
if (__are_doubles_equal(value, fp_range.from_value) || __are_doubles_equal(value,
|
||||
fp_range.to_value))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
if ((value < fp_range.from_value) || (value > fp_range.to_value)) {
|
||||
result.successful = false;
|
||||
result.reason = format_range_reason(descriptor.name, "floating point");
|
||||
return result;
|
||||
}
|
||||
if (fp_range.step == 0.0) {
|
||||
return result;
|
||||
}
|
||||
double rounded_div = std::round((value - fp_range.from_value) / fp_range.step);
|
||||
if (__are_doubles_equal(value, fp_range.from_value + rounded_div * fp_range.step)) {
|
||||
return result;
|
||||
}
|
||||
result.successful = false;
|
||||
result.reason = format_range_reason(descriptor.name, "floating point");
|
||||
return result;
|
||||
}
|
||||
|
||||
RCLCPP_LOCAL
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
__check_parameter_value_in_range(
|
||||
@@ -260,39 +201,49 @@ __check_parameter_value_in_range(
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER) {
|
||||
result = __check_integer_range(descriptor, value.get<int64_t>());
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!descriptor.integer_range.empty() && value.get_type() == rclcpp::PARAMETER_INTEGER_ARRAY) {
|
||||
std::vector<int64_t> val_array = value.get<std::vector<int64_t>>();
|
||||
for (const int64_t & val : val_array) {
|
||||
result = __check_integer_range(descriptor, val);
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
int64_t v = value.get<int64_t>();
|
||||
auto integer_range = descriptor.integer_range.at(0);
|
||||
if (v == integer_range.from_value || v == integer_range.to_value) {
|
||||
return result;
|
||||
}
|
||||
if ((v < integer_range.from_value) || (v > integer_range.to_value)) {
|
||||
result.successful = false;
|
||||
result.reason = format_range_reason(descriptor.name, "integer");
|
||||
return result;
|
||||
}
|
||||
if (integer_range.step == 0) {
|
||||
return result;
|
||||
}
|
||||
if (((v - integer_range.from_value) % integer_range.step) == 0) {
|
||||
return result;
|
||||
}
|
||||
result.successful = false;
|
||||
result.reason = format_range_reason(descriptor.name, "integer");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!descriptor.floating_point_range.empty() && value.get_type() == rclcpp::PARAMETER_DOUBLE) {
|
||||
result = __check_double_range(descriptor, value.get<double>());
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!descriptor.floating_point_range.empty() &&
|
||||
value.get_type() == rclcpp::PARAMETER_DOUBLE_ARRAY)
|
||||
{
|
||||
std::vector<double> val_array = value.get<std::vector<double>>();
|
||||
for (const double & val : val_array) {
|
||||
result = __check_double_range(descriptor, val);
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
double v = value.get<double>();
|
||||
auto fp_range = descriptor.floating_point_range.at(0);
|
||||
if (__are_doubles_equal(v, fp_range.from_value) || __are_doubles_equal(v, fp_range.to_value)) {
|
||||
return result;
|
||||
}
|
||||
if ((v < fp_range.from_value) || (v > fp_range.to_value)) {
|
||||
result.successful = false;
|
||||
result.reason = format_range_reason(descriptor.name, "floating point");
|
||||
return result;
|
||||
}
|
||||
if (fp_range.step == 0.0) {
|
||||
return result;
|
||||
}
|
||||
double rounded_div = std::round((v - fp_range.from_value) / fp_range.step);
|
||||
if (__are_doubles_equal(v, fp_range.from_value + rounded_div * fp_range.step)) {
|
||||
return result;
|
||||
}
|
||||
result.successful = false;
|
||||
result.reason = format_range_reason(descriptor.name, "floating point");
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
// 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 "rclcpp/parameter_descriptor_wrapper.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
ParameterDescription::ParameterDescription()
|
||||
{
|
||||
// Need to set this in the constructor, but it doesn't necessarily need to be used
|
||||
parameter_descriptor.type = rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET;
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::ParameterDescriptor ParameterDescription::build() const
|
||||
{
|
||||
// Return some some sort message
|
||||
return parameter_descriptor;
|
||||
}
|
||||
|
||||
// Builder methods which set up the original class
|
||||
// They all follow the same format of initing the value given within the base class
|
||||
// then returning the current class
|
||||
ParameterDescription & ParameterDescription::set_name(const std::string & name)
|
||||
{
|
||||
parameter_descriptor.name = name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ParameterDescription & ParameterDescription::set_type(std::uint8_t type)
|
||||
{
|
||||
parameter_descriptor.type = type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ParameterDescription & ParameterDescription::set_description_text(const std::string & description)
|
||||
{
|
||||
parameter_descriptor.description = description;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ParameterDescription & ParameterDescription::set_additional_constraints(
|
||||
const std::string & constraints)
|
||||
{
|
||||
parameter_descriptor.additional_constraints = constraints;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ParameterDescription & ParameterDescription::set_read_only(bool read_only)
|
||||
{
|
||||
parameter_descriptor.read_only = read_only;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ParameterDescription & ParameterDescription::set_dynamic_typing(bool dynamic_typing)
|
||||
{
|
||||
parameter_descriptor.dynamic_typing = dynamic_typing;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Here is the Specific range function for this parameter description
|
||||
ParameterDescription & ParameterDescription::set_floating_point_description_range(
|
||||
float min, float max, float step)
|
||||
{
|
||||
if (parameter_descriptor.type == rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE) {
|
||||
parameter_descriptor.floating_point_range.resize(1);
|
||||
parameter_descriptor.floating_point_range.at(0).from_value = min;
|
||||
parameter_descriptor.floating_point_range.at(0).to_value = max;
|
||||
parameter_descriptor.floating_point_range.at(0).step = step;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ParameterDescription & ParameterDescription::set_integer_description_range(
|
||||
int min, int max, int step)
|
||||
{
|
||||
if (parameter_descriptor.type == rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER) {
|
||||
parameter_descriptor.integer_range.resize(1);
|
||||
parameter_descriptor.integer_range.at(0).from_value = min;
|
||||
parameter_descriptor.integer_range.at(0).to_value = max;
|
||||
parameter_descriptor.integer_range.at(0).step = step;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
@@ -74,38 +74,6 @@ ParameterEventHandler::add_parameter_callback(
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool
|
||||
ParameterEventHandler::configure_nodes_filter(const std::vector<std::string> & node_names)
|
||||
{
|
||||
if (node_names.empty()) {
|
||||
// Clear content filter
|
||||
event_subscription_->set_content_filter("");
|
||||
if (event_subscription_->is_cft_enabled()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string filter_expression;
|
||||
size_t total = node_names.size();
|
||||
for (size_t i = 0; i < total; ++i) {
|
||||
filter_expression += "node = %" + std::to_string(i);
|
||||
if (i < total - 1) {
|
||||
filter_expression += " OR ";
|
||||
}
|
||||
}
|
||||
|
||||
// Enclose each node name in "'".
|
||||
std::vector<std::string> quoted_node_names;
|
||||
for (const auto & name : node_names) {
|
||||
quoted_node_names.push_back("'" + resolve_path(name) + "'");
|
||||
}
|
||||
|
||||
event_subscription_->set_content_filter(filter_expression, quoted_node_names);
|
||||
|
||||
return event_subscription_->is_cft_enabled();
|
||||
}
|
||||
|
||||
void
|
||||
ParameterEventHandler::remove_parameter_callback(
|
||||
ParameterCallbackHandle::SharedPtr callback_handle)
|
||||
|
||||
@@ -44,9 +44,9 @@ rclcpp::to_string(const ParameterType type)
|
||||
return "double_array";
|
||||
case ParameterType::PARAMETER_STRING_ARRAY:
|
||||
return "string_array";
|
||||
default:
|
||||
return "unknown type";
|
||||
}
|
||||
|
||||
return "unknown type";
|
||||
}
|
||||
|
||||
std::ostream &
|
||||
@@ -103,9 +103,9 @@ rclcpp::to_string(const ParameterValue & value)
|
||||
return array_to_string(value.get<std::vector<double>>());
|
||||
case ParameterType::PARAMETER_STRING_ARRAY:
|
||||
return array_to_string(value.get<std::vector<std::string>>());
|
||||
default:
|
||||
return "unknown type";
|
||||
}
|
||||
|
||||
return "unknown type";
|
||||
}
|
||||
|
||||
ParameterValue::ParameterValue()
|
||||
|
||||
@@ -40,12 +40,6 @@ std::string qos_policy_name_from_kind(rmw_qos_policy_kind_t policy_kind)
|
||||
return "HISTORY_QOS_POLICY";
|
||||
case RMW_QOS_POLICY_LIFESPAN:
|
||||
return "LIFESPAN_QOS_POLICY";
|
||||
case RMW_QOS_POLICY_DEPTH:
|
||||
return "DEPTH_QOS_POLICY";
|
||||
case RMW_QOS_POLICY_LIVELINESS_LEASE_DURATION:
|
||||
return "LIVELINESS_LEASE_DURATION_QOS_POLICY";
|
||||
case RMW_QOS_POLICY_AVOID_ROS_NAMESPACE_CONVENTIONS:
|
||||
return "AVOID_ROS_NAMESPACE_CONVENTIONS_QOS_POLICY";
|
||||
default:
|
||||
return "INVALID_QOS_POLICY";
|
||||
}
|
||||
|
||||
@@ -67,13 +67,7 @@ Rate::sleep()
|
||||
// Calculate the time to sleep
|
||||
auto time_to_sleep = next_interval - now;
|
||||
// Sleep (will get interrupted by ctrl-c, may not sleep full time)
|
||||
try {
|
||||
// If the context is invalid, an exception will be thrown.
|
||||
clock_->sleep_for(time_to_sleep);
|
||||
} catch (const std::runtime_error & e) {
|
||||
// If it didn't sleep the full time, return false
|
||||
return false;
|
||||
}
|
||||
clock_->sleep_for(time_to_sleep);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ SignalHandler::signal_handler(
|
||||
old_signal_handler.sa_handler(signum);
|
||||
}
|
||||
}
|
||||
instance.signal_handler_common(signum);
|
||||
instance.signal_handler_common();
|
||||
}
|
||||
#else
|
||||
void
|
||||
@@ -98,7 +98,7 @@ SignalHandler::signal_handler(int signum)
|
||||
{
|
||||
old_signal_handler(signum);
|
||||
}
|
||||
instance.signal_handler_common(signum);
|
||||
instance.signal_handler_common();
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -243,10 +243,9 @@ SignalHandler::get_old_signal_handler(int signum)
|
||||
}
|
||||
|
||||
void
|
||||
SignalHandler::signal_handler_common(int signum)
|
||||
SignalHandler::signal_handler_common()
|
||||
{
|
||||
auto & instance = SignalHandler::get_global_signal_handler();
|
||||
instance.signal_number_.store(signum);
|
||||
instance.signal_received_.store(true);
|
||||
instance.notify_signal_handler();
|
||||
}
|
||||
@@ -256,8 +255,7 @@ SignalHandler::deferred_signal_handler()
|
||||
{
|
||||
while (true) {
|
||||
if (signal_received_.exchange(false)) {
|
||||
int signum = signal_number_.load();
|
||||
RCLCPP_INFO(get_logger(), "signal_handler(signum=%d)", signum);
|
||||
RCLCPP_INFO(SignalHandler::get_logger(), "signal_handler(SIGINT/SIGTERM)");
|
||||
RCLCPP_DEBUG(get_logger(), "deferred_signal_handler(): shutting down");
|
||||
for (auto context_ptr : rclcpp::get_contexts()) {
|
||||
if (context_ptr->get_init_options().shutdown_on_signal) {
|
||||
|
||||
@@ -116,7 +116,7 @@ private:
|
||||
|
||||
/// Common signal handler code between sigaction and non-sigaction versions.
|
||||
void
|
||||
signal_handler_common(int signum);
|
||||
signal_handler_common();
|
||||
|
||||
#if defined(RCLCPP_HAS_SIGACTION)
|
||||
/// Signal handler function.
|
||||
@@ -189,8 +189,6 @@ private:
|
||||
|
||||
// Whether or not a signal has been received.
|
||||
std::atomic_bool signal_received_ = false;
|
||||
// The signal number that was received.
|
||||
std::atomic_int signal_number_ = 0;
|
||||
// A thread to which signal handling tasks are deferred.
|
||||
std::thread signal_handler_thread_;
|
||||
|
||||
|
||||
@@ -577,26 +577,3 @@ SubscriptionBase::take_dynamic_message(
|
||||
throw std::runtime_error("Unimplemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SubscriptionBase::disable_callbacks()
|
||||
{
|
||||
// Temporary remove the on_new_message_callback_ to prevent it from being called
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
|
||||
if (on_new_message_callback_) {
|
||||
set_on_new_message_callback(nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SubscriptionBase::enable_callbacks()
|
||||
{
|
||||
// Set callback again if it was previously removed in disable_callbacks()
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
|
||||
if (on_new_message_callback_) {
|
||||
set_on_new_message_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<
|
||||
decltype(on_new_message_callback_), const void *, size_t>,
|
||||
static_cast<const void *>(&on_new_message_callback_));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,17 +40,3 @@ SubscriptionIntraProcessBase::is_durability_transient_local() const
|
||||
{
|
||||
return qos_profile_.durability() == rclcpp::DurabilityPolicy::TransientLocal;
|
||||
}
|
||||
|
||||
void
|
||||
SubscriptionIntraProcessBase::disable_callbacks()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
|
||||
on_new_message_callback_disabled_ = true;
|
||||
}
|
||||
|
||||
void
|
||||
SubscriptionIntraProcessBase::enable_callbacks()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
|
||||
on_new_message_callback_disabled_ = false;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include "rclcpp/typesupport_helpers.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
@@ -74,21 +73,6 @@ const void * get_typesupport_handle_impl(
|
||||
}
|
||||
}
|
||||
|
||||
// Trim leading and trailing whitespace from the string.
|
||||
std::string string_trim(std::string_view str_v)
|
||||
{
|
||||
auto begin = std::find_if_not(str_v.begin(), str_v.end(), [](unsigned char ch) {
|
||||
return std::isspace(ch);
|
||||
});
|
||||
auto end = std::find_if_not(str_v.rbegin(), str_v.rend(), [](unsigned char ch) {
|
||||
return std::isspace(ch);
|
||||
}).base();
|
||||
if (begin >= end) {
|
||||
return {};
|
||||
}
|
||||
return std::string(begin, end);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
std::tuple<std::string, std::string, std::string>
|
||||
@@ -98,7 +82,6 @@ extract_type_identifier(const std::string & full_type)
|
||||
auto sep_position_back = full_type.find_last_of(type_separator);
|
||||
auto sep_position_front = full_type.find_first_of(type_separator);
|
||||
if (sep_position_back == std::string::npos ||
|
||||
sep_position_front == 0 ||
|
||||
sep_position_back == 0 ||
|
||||
sep_position_back == full_type.length() - 1)
|
||||
{
|
||||
@@ -114,8 +97,7 @@ extract_type_identifier(const std::string & full_type)
|
||||
}
|
||||
std::string type_name = full_type.substr(sep_position_back + 1);
|
||||
|
||||
return std::make_tuple(
|
||||
string_trim(package_name), string_trim(middle_module), string_trim(type_name));
|
||||
return std::make_tuple(package_name, middle_module, type_name);
|
||||
}
|
||||
|
||||
std::string get_typesupport_library_path(
|
||||
@@ -123,27 +105,27 @@ std::string get_typesupport_library_path(
|
||||
{
|
||||
const char * dynamic_library_folder;
|
||||
#ifdef _WIN32
|
||||
dynamic_library_folder = "bin";
|
||||
dynamic_library_folder = "/bin/";
|
||||
#elif __APPLE__
|
||||
dynamic_library_folder = "lib";
|
||||
dynamic_library_folder = "/lib/";
|
||||
#else
|
||||
dynamic_library_folder = "lib";
|
||||
dynamic_library_folder = "/lib/";
|
||||
#endif
|
||||
|
||||
std::filesystem::path package_prefix;
|
||||
std::string package_prefix;
|
||||
try {
|
||||
ament_index_cpp::get_package_prefix(package_name, package_prefix);
|
||||
package_prefix = ament_index_cpp::get_package_prefix(package_name);
|
||||
} catch (ament_index_cpp::PackageNotFoundError & e) {
|
||||
throw std::runtime_error(e.what());
|
||||
}
|
||||
|
||||
const std::string library_path = rcpputils::path_for_library(
|
||||
(package_prefix / dynamic_library_folder).string(),
|
||||
package_prefix + dynamic_library_folder,
|
||||
package_name + "__" + typesupport_identifier);
|
||||
if (library_path.empty()) {
|
||||
throw std::runtime_error(
|
||||
"Typesupport library for " + package_name + " does not exist in '" +
|
||||
package_prefix.string() + "'.");
|
||||
"Typesupport library for " + package_name + " does not exist in '" + package_prefix +
|
||||
"'.");
|
||||
}
|
||||
return library_path;
|
||||
}
|
||||
|
||||
@@ -125,13 +125,11 @@ BENCHMARK_F(ServicePerformanceTest, async_send_response)(benchmark::State & stat
|
||||
auto service = node->create_service<test_msgs::srv::Empty>(empty_service_name, callback);
|
||||
|
||||
reset_heap_counters();
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node->get_node_base_interface());
|
||||
for (auto _ : state) {
|
||||
(void)_;
|
||||
state.PauseTiming();
|
||||
// Clear executor queue
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node->get_node_base_interface());
|
||||
|
||||
auto request = std::make_shared<test_msgs::srv::Empty::Request>();
|
||||
auto future = empty_client->async_send_request(request);
|
||||
@@ -139,7 +137,7 @@ BENCHMARK_F(ServicePerformanceTest, async_send_response)(benchmark::State & stat
|
||||
benchmark::DoNotOptimize(service);
|
||||
benchmark::ClobberMemory();
|
||||
|
||||
executor.spin_until_future_complete(future);
|
||||
rclcpp::spin_until_future_complete(node->get_node_base_interface(), future);
|
||||
}
|
||||
if (callback_count == 0) {
|
||||
state.SkipWithError("Service callback was not called");
|
||||
|
||||
@@ -57,6 +57,11 @@ ament_add_test_label(test_client mimick)
|
||||
if(TARGET test_client)
|
||||
target_link_libraries(test_client ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_clock test_clock.cpp)
|
||||
ament_add_test_label(test_clock mimick)
|
||||
if(TARGET test_clock)
|
||||
target_link_libraries(test_clock ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_clock_conditional test_clock_conditional.cpp)
|
||||
ament_add_test_label(test_clock_conditional mimick)
|
||||
if(TARGET test_clock_conditional)
|
||||
@@ -529,6 +534,13 @@ if(TARGET test_executors_warmup)
|
||||
target_link_libraries(test_executors_warmup ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_static_single_threaded_executor executors/test_static_single_threaded_executor.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
ament_add_test_label(test_static_single_threaded_executor mimick)
|
||||
if(TARGET test_static_single_threaded_executor)
|
||||
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_multi_threaded_executor executors/test_multi_threaded_executor.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_multi_threaded_executor)
|
||||
@@ -662,24 +674,32 @@ endif()
|
||||
function(test_on_all_rmws)
|
||||
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
|
||||
|
||||
ament_add_ros_isolated_gmock_test(test_qos_event
|
||||
# If the rmw_implementation is rmw_zenoh_cpp, run the tests with multicast discovery enabled.
|
||||
# Note: This is a temporary change that will be reverted before we branch into Kilted.
|
||||
if(rmw_implementation STREQUAL "rmw_zenoh_cpp")
|
||||
list(APPEND rmw_implementation_env_var
|
||||
ZENOH_CONFIG_OVERRIDE=scouting/multicast/enabled=true
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_add_gmock_test(test_qos_event
|
||||
TEST_NAME test_qos_event${target_suffix}
|
||||
ENV ${rmw_implementation_env_var}
|
||||
)
|
||||
ament_add_test_label(test_qos_event${target_suffix} mimick)
|
||||
|
||||
ament_add_ros_isolated_gmock_test(test_generic_pubsub
|
||||
ament_add_gmock_test(test_generic_pubsub
|
||||
TEST_NAME test_generic_pubsub${target_suffix}
|
||||
ENV ${rmw_implementation_env_var}
|
||||
)
|
||||
|
||||
ament_add_ros_isolated_gmock_test(test_add_callback_groups_to_executor
|
||||
ament_add_gmock_test(test_add_callback_groups_to_executor
|
||||
TEST_NAME test_add_callback_groups_to_executor${target_suffix}
|
||||
ENV ${rmw_implementation_env_var}
|
||||
TIMEOUT 120
|
||||
)
|
||||
|
||||
ament_add_ros_isolated_gmock_test(test_subscription_content_filter
|
||||
ament_add_gmock_test(test_subscription_content_filter
|
||||
TEST_NAME test_subscription_content_filter${target_suffix}
|
||||
ENV ${rmw_implementation_env_var}
|
||||
TIMEOUT 120
|
||||
|
||||
@@ -22,13 +22,40 @@
|
||||
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
|
||||
#include "rclcpp/executors/single_threaded_executor.hpp"
|
||||
#include "rclcpp/executors/static_single_threaded_executor.hpp"
|
||||
#include "rclcpp/executors/multi_threaded_executor.hpp"
|
||||
|
||||
// suppress deprecated StaticSingleThreadedExecutor warning
|
||||
// we define an alias that explicitly indicates that this class is deprecated, while avoiding
|
||||
// polluting a lot of files the gcc pragmas
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
using DeprecatedStaticSingleThreadedExecutor = rclcpp::executors::StaticSingleThreadedExecutor;
|
||||
// remove warning suppression
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
using ExecutorTypes =
|
||||
::testing::Types<
|
||||
rclcpp::executors::SingleThreadedExecutor,
|
||||
rclcpp::executors::MultiThreadedExecutor,
|
||||
DeprecatedStaticSingleThreadedExecutor,
|
||||
rclcpp::experimental::executors::EventsExecutor>;
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
class ExecutorTypeNames
|
||||
{
|
||||
@@ -43,6 +70,16 @@ public:
|
||||
if (std::is_same<T, rclcpp::executors::MultiThreadedExecutor>()) {
|
||||
return "MultiThreadedExecutor";
|
||||
}
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
if (std::is_same<T, DeprecatedStaticSingleThreadedExecutor>()) {
|
||||
return "StaticSingleThreadedExecutor";
|
||||
}
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
if (std::is_same<T, rclcpp::experimental::executors::EventsExecutor>()) {
|
||||
return "EventsExecutor";
|
||||
@@ -52,6 +89,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// StaticSingleThreadedExecutor is not included in these tests for now, due to:
|
||||
// https://github.com/ros2/rclcpp/issues/1219
|
||||
using StandardExecutors =
|
||||
::testing::Types<
|
||||
rclcpp::executors::SingleThreadedExecutor,
|
||||
|
||||
@@ -804,10 +804,8 @@ TEST(TestExecutors, testSpinUntilFutureCompleteNodePtr)
|
||||
}
|
||||
|
||||
// Check spin functions with non default context
|
||||
TYPED_TEST(TestExecutors, testSpinWithNonDefaultContext)
|
||||
TEST(TestExecutors, testSpinWithNonDefaultContext)
|
||||
{
|
||||
using ExecutorType = TypeParam;
|
||||
|
||||
auto non_default_context = std::make_shared<rclcpp::Context>();
|
||||
non_default_context->init(0, nullptr);
|
||||
|
||||
@@ -815,14 +813,9 @@ TYPED_TEST(TestExecutors, testSpinWithNonDefaultContext)
|
||||
auto node =
|
||||
std::make_unique<rclcpp::Node>("node", rclcpp::NodeOptions().context(non_default_context));
|
||||
|
||||
rclcpp::ExecutorOptions options;
|
||||
options.context = non_default_context;
|
||||
ExecutorType executor(options);
|
||||
EXPECT_NO_THROW(executor.add_node(node->get_node_base_interface()));
|
||||
EXPECT_NO_THROW(rclcpp::spin_some(node->get_node_base_interface()));
|
||||
|
||||
EXPECT_NO_THROW(executor.spin_some());
|
||||
|
||||
EXPECT_NO_THROW(executor.spin_all(1s));
|
||||
EXPECT_NO_THROW(rclcpp::spin_all(node->get_node_base_interface(), 1s));
|
||||
|
||||
auto check_spin_until_future_complete = [&]() {
|
||||
std::promise<bool> promise;
|
||||
@@ -830,7 +823,8 @@ TYPED_TEST(TestExecutors, testSpinWithNonDefaultContext)
|
||||
promise.set_value(true);
|
||||
|
||||
auto shared_future = future.share();
|
||||
auto ret = executor.spin_until_future_complete(shared_future, 1s);
|
||||
auto ret = rclcpp::spin_until_future_complete(
|
||||
node->get_node_base_interface(), shared_future, 1s);
|
||||
EXPECT_EQ(rclcpp::FutureReturnCode::SUCCESS, ret);
|
||||
};
|
||||
EXPECT_NO_THROW(check_spin_until_future_complete());
|
||||
|
||||
@@ -285,11 +285,20 @@ public:
|
||||
T executor;
|
||||
};
|
||||
|
||||
#if !defined(_WIN32)
|
||||
# ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
# endif
|
||||
#endif
|
||||
using MainExecutorTypes =
|
||||
::testing::Types<
|
||||
rclcpp::executors::SingleThreadedExecutor,
|
||||
rclcpp::executors::MultiThreadedExecutor>;
|
||||
|
||||
rclcpp::executors::MultiThreadedExecutor,
|
||||
DeprecatedStaticSingleThreadedExecutor>;
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
// TODO(@fujitatomoya): this test excludes EventExecutor because it does not
|
||||
// support simulation time used for this test to relax the racy condition.
|
||||
// See more details for https://github.com/ros2/rclcpp/issues/2457.
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
// Copyright 2020 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 <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/executors.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "test_msgs/srv/empty.hpp"
|
||||
|
||||
#include "./executor_types.hpp"
|
||||
#include "../../mocking_utils/patch.hpp"
|
||||
#include "../../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class TestStaticSingleThreadedExecutor : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
void SetUp()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestStaticSingleThreadedExecutor, add_callback_group_trigger_guard_failed) {
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
DeprecatedStaticSingleThreadedExecutor executor;
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
|
||||
{
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
executor.add_callback_group(cb_group, node->get_node_base_interface(), true),
|
||||
std::runtime_error("Failed to handle entities update on callback group add: error not set"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestStaticSingleThreadedExecutor, add_node_trigger_guard_failed) {
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
DeprecatedStaticSingleThreadedExecutor executor;
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
|
||||
{
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
executor.add_node(node),
|
||||
std::runtime_error("Failed to handle entities update on node add: error not set"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestStaticSingleThreadedExecutor, remove_callback_group_trigger_guard_failed) {
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
DeprecatedStaticSingleThreadedExecutor executor;
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
rclcpp::CallbackGroup::SharedPtr cb_group = node->create_callback_group(
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
|
||||
executor.add_callback_group(cb_group, node->get_node_base_interface(), true);
|
||||
|
||||
{
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
executor.remove_callback_group(cb_group, true),
|
||||
std::runtime_error(
|
||||
"Failed to handle entities update on callback group remove: error not set"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestStaticSingleThreadedExecutor, remove_node_failed) {
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
DeprecatedStaticSingleThreadedExecutor executor;
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
|
||||
{
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
executor.remove_node(node, true),
|
||||
std::runtime_error("Node '/ns/node' needs to be associated with an executor."));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestStaticSingleThreadedExecutor, remove_node_trigger_guard_failed) {
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
DeprecatedStaticSingleThreadedExecutor executor;
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
|
||||
executor.add_node(node);
|
||||
|
||||
{
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp", rcl_trigger_guard_condition, RCL_RET_ERROR);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
executor.remove_node(node, true),
|
||||
std::runtime_error("Failed to handle entities update on node remove: error not set"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestStaticSingleThreadedExecutor, execute_service) {
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
DeprecatedStaticSingleThreadedExecutor executor;
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
executor.add_node(node);
|
||||
|
||||
auto service =
|
||||
node->create_service<test_msgs::srv::Empty>(
|
||||
"service",
|
||||
[](
|
||||
const test_msgs::srv::Empty::Request::SharedPtr,
|
||||
test_msgs::srv::Empty::Response::SharedPtr) {});
|
||||
auto client = node->create_client<test_msgs::srv::Empty>("service");
|
||||
|
||||
std::promise<void> promise;
|
||||
std::future<void> future = promise.get_future();
|
||||
EXPECT_EQ(
|
||||
rclcpp::FutureReturnCode::TIMEOUT,
|
||||
executor.spin_until_future_complete(future, std::chrono::milliseconds(1)));
|
||||
|
||||
executor.remove_node(node);
|
||||
executor.spin_until_future_complete(future, std::chrono::milliseconds(1));
|
||||
}
|
||||
@@ -510,9 +510,7 @@ TEST_F(TestNodeGraph, get_node_names_and_namespaces_fini_errors)
|
||||
"lib:rclcpp", rcutils_string_array_fini, RCL_RET_ERROR);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
node_graph()->get_node_names_and_namespaces(),
|
||||
std::runtime_error(
|
||||
"could not destroy node names: error not set, "
|
||||
"could not destroy node namespaces: error not set"));
|
||||
std::runtime_error("could not destroy node names, could not destroy node namespaces"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeGraph, get_node_names_with_enclaves_fini_errors)
|
||||
|
||||
@@ -94,8 +94,6 @@ public:
|
||||
void handle_dynamic_message(
|
||||
const DynamicMessage::SharedPtr &,
|
||||
const rclcpp::MessageInfo &) override {}
|
||||
void disable_callbacks() override {}
|
||||
void enable_callbacks() override {}
|
||||
};
|
||||
|
||||
class TestNodeTopics : public ::testing::Test
|
||||
|
||||
@@ -808,8 +808,7 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_service_out_of_scope) {
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
}
|
||||
// service is out of scope here, so should be cleaned up already.
|
||||
EXPECT_EQ(0u, allocator_memory_strategy()->number_of_ready_services());
|
||||
EXPECT_EQ(1u, allocator_memory_strategy()->number_of_ready_services());
|
||||
|
||||
rclcpp::AnyExecutable result;
|
||||
allocator_memory_strategy()->get_next_service(result, weak_groups_to_nodes);
|
||||
@@ -844,8 +843,7 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_client_out_of_scope) {
|
||||
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
}
|
||||
// client is out of scope here, so should be cleaned up already.
|
||||
EXPECT_EQ(0u, allocator_memory_strategy()->number_of_ready_clients());
|
||||
EXPECT_EQ(1u, allocator_memory_strategy()->number_of_ready_clients());
|
||||
|
||||
rclcpp::AnyExecutable result;
|
||||
allocator_memory_strategy()->get_next_client(result, weak_groups_to_nodes);
|
||||
@@ -873,8 +871,7 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_timer_out_of_scope) {
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
}
|
||||
// timer is out of scope here, so should be cleaned up already.
|
||||
EXPECT_EQ(0u, allocator_memory_strategy()->number_of_ready_timers());
|
||||
EXPECT_EQ(1u, allocator_memory_strategy()->number_of_ready_timers());
|
||||
|
||||
rclcpp::AnyExecutable result;
|
||||
allocator_memory_strategy()->get_next_timer(result, weak_groups_to_nodes);
|
||||
|
||||
@@ -14,13 +14,11 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#define RCLCPP_AVOID_DEPRECATIONS_FOR_UNIT_TESTS 1
|
||||
#include "rclcpp/any_subscription_callback.hpp"
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
|
||||
@@ -179,7 +177,7 @@ TEST_F(TestAnySubscriptionCallback, is_serialized_message_callback) {
|
||||
}
|
||||
{
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
|
||||
asc.set([](std::shared_ptr<const rclcpp::SerializedMessage>) {});
|
||||
asc.set([](std::shared_ptr<rclcpp::SerializedMessage>) {});
|
||||
EXPECT_TRUE(asc.is_serialized_message_callback());
|
||||
EXPECT_NO_THROW(
|
||||
asc.dispatch(
|
||||
@@ -188,7 +186,7 @@ TEST_F(TestAnySubscriptionCallback, is_serialized_message_callback) {
|
||||
}
|
||||
{
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
|
||||
asc.set([](std::shared_ptr<const rclcpp::SerializedMessage>, const rclcpp::MessageInfo &) {});
|
||||
asc.set([](std::shared_ptr<rclcpp::SerializedMessage>, const rclcpp::MessageInfo &) {});
|
||||
EXPECT_TRUE(asc.is_serialized_message_callback());
|
||||
EXPECT_NO_THROW(
|
||||
asc.dispatch(
|
||||
@@ -209,126 +207,6 @@ TEST_F(TestAnySubscriptionCallback, unset_dispatch_throw) {
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
//
|
||||
// Testing disable and enable callbacks
|
||||
//
|
||||
TEST_F(TestAnySubscriptionCallback, disable_enable_callbacks) {
|
||||
std::atomic<int> callback_count{0};
|
||||
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
|
||||
asc.set([&callback_count](const test_msgs::msg::Empty &) {
|
||||
++callback_count;
|
||||
});
|
||||
|
||||
// Callback should work initially
|
||||
asc.dispatch(msg_shared_ptr_, message_info_);
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Disable and verify callback is not called
|
||||
asc.disable();
|
||||
asc.dispatch(msg_shared_ptr_, message_info_);
|
||||
EXPECT_EQ(1, callback_count.load()); // Count should not increase
|
||||
|
||||
// Enable and verify callback works again
|
||||
asc.enable();
|
||||
asc.dispatch(msg_shared_ptr_, message_info_);
|
||||
EXPECT_EQ(2, callback_count.load());
|
||||
}
|
||||
|
||||
TEST_F(TestAnySubscriptionCallback, disable_enable_callbacks_intra_process) {
|
||||
std::atomic<int> callback_count{0};
|
||||
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
|
||||
asc.set([&callback_count](std::shared_ptr<const test_msgs::msg::Empty>) {
|
||||
++callback_count;
|
||||
});
|
||||
|
||||
// Callback should work initially
|
||||
asc.dispatch_intra_process(msg_shared_ptr_, message_info_);
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Disable and verify callback is not called
|
||||
asc.disable();
|
||||
asc.dispatch_intra_process(msg_shared_ptr_, message_info_);
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Enable and verify callback works again
|
||||
asc.enable();
|
||||
asc.dispatch_intra_process(msg_shared_ptr_, message_info_);
|
||||
EXPECT_EQ(2, callback_count.load());
|
||||
}
|
||||
|
||||
TEST_F(TestAnySubscriptionCallback, disable_enable_callbacks_unique_ptr) {
|
||||
std::atomic<int> callback_count{0};
|
||||
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
|
||||
asc.set([&callback_count](std::unique_ptr<test_msgs::msg::Empty>) {
|
||||
++callback_count;
|
||||
});
|
||||
|
||||
// Callback should work initially
|
||||
asc.dispatch_intra_process(get_unique_ptr_msg(), message_info_);
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Disable and verify callback is not called
|
||||
asc.disable();
|
||||
asc.dispatch_intra_process(get_unique_ptr_msg(), message_info_);
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Enable and verify callback works again
|
||||
asc.enable();
|
||||
asc.dispatch_intra_process(get_unique_ptr_msg(), message_info_);
|
||||
EXPECT_EQ(2, callback_count.load());
|
||||
}
|
||||
|
||||
TEST_F(TestAnySubscriptionCallback, disable_enable_serialized_message) {
|
||||
std::atomic<int> callback_count{0};
|
||||
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
|
||||
asc.set([&callback_count](const rclcpp::SerializedMessage &) {
|
||||
++callback_count;
|
||||
});
|
||||
|
||||
auto serialized_msg = std::make_shared<rclcpp::SerializedMessage>();
|
||||
|
||||
// Callback should work initially
|
||||
asc.dispatch(serialized_msg, message_info_);
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Disable and verify callback is not called
|
||||
asc.disable();
|
||||
asc.dispatch(serialized_msg, message_info_);
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Enable and verify callback works again
|
||||
asc.enable();
|
||||
asc.dispatch(serialized_msg, message_info_);
|
||||
EXPECT_EQ(2, callback_count.load());
|
||||
}
|
||||
|
||||
TEST_F(TestAnySubscriptionCallbackTA, disable_enable_callbacks_type_adapter) {
|
||||
std::atomic<int> callback_count{0};
|
||||
|
||||
rclcpp::AnySubscriptionCallback<MyTA> asc;
|
||||
asc.set([&callback_count](const MyEmpty &) {
|
||||
++callback_count;
|
||||
});
|
||||
|
||||
// Callback should work initially
|
||||
asc.dispatch_intra_process(msg_shared_ptr_, message_info_);
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Disable and verify callback is not called
|
||||
asc.disable();
|
||||
asc.dispatch_intra_process(msg_shared_ptr_, message_info_);
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Enable and verify callback works again
|
||||
asc.enable();
|
||||
asc.dispatch_intra_process(msg_shared_ptr_, message_info_);
|
||||
EXPECT_EQ(2, callback_count.load());
|
||||
}
|
||||
|
||||
//
|
||||
// Parameterized test to test across all callback types and dispatch types.
|
||||
//
|
||||
|
||||
@@ -112,12 +112,10 @@ protected:
|
||||
auto req_id = client->async_send_request(request, std::move(callback));
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
while (!received_response &&
|
||||
(std::chrono::steady_clock::now() - start) < timeout)
|
||||
{
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
if (!received_response) {
|
||||
@@ -358,12 +356,10 @@ TYPED_TEST(TestAllClientTypesWithServer, on_new_response_callback)
|
||||
|
||||
this->template async_send_request<ClientType, test_msgs::srv::Empty::Request>(client, request);
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(server_node);
|
||||
while (server_requests_count == 0 &&
|
||||
(std::chrono::steady_clock::now() - start) < std::chrono::seconds(10))
|
||||
{
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(server_node);
|
||||
}
|
||||
|
||||
ASSERT_EQ(server_requests_count, 1u);
|
||||
@@ -384,7 +380,7 @@ TYPED_TEST(TestAllClientTypesWithServer, on_new_response_callback)
|
||||
while (server_requests_count == 1 &&
|
||||
(std::chrono::steady_clock::now() - start) < std::chrono::seconds(10))
|
||||
{
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(server_node);
|
||||
}
|
||||
|
||||
ASSERT_EQ(server_requests_count, 2u);
|
||||
@@ -406,7 +402,7 @@ TYPED_TEST(TestAllClientTypesWithServer, on_new_response_callback)
|
||||
while (server_requests_count < 5 &&
|
||||
(std::chrono::steady_clock::now() - start) < std::chrono::seconds(10))
|
||||
{
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(server_node);
|
||||
}
|
||||
|
||||
ASSERT_EQ(server_requests_count, 5u);
|
||||
@@ -496,12 +492,10 @@ void client_async_send_request_callback_with_request(
|
||||
auto req_id = client->async_send_request(request, std::move(callback));
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
while (!received_response &&
|
||||
(std::chrono::steady_clock::now() - start) < std::chrono::seconds(1))
|
||||
{
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
EXPECT_TRUE(received_response);
|
||||
EXPECT_FALSE(client->remove_pending_request(req_id));
|
||||
@@ -559,29 +553,25 @@ void client_qos_depth(rclcpp::Node::SharedPtr node)
|
||||
}
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
rclcpp::executors::SingleThreadedExecutor server_executor;
|
||||
server_executor.add_node(server_node);
|
||||
while ((server_cb_count_ < client_requests) &&
|
||||
(std::chrono::steady_clock::now() - start) < 2s)
|
||||
{
|
||||
server_executor.spin_some();
|
||||
rclcpp::spin_some(server_node);
|
||||
std::this_thread::sleep_for(2ms);
|
||||
}
|
||||
|
||||
EXPECT_GT(server_cb_count_, client_qos_profile.depth());
|
||||
|
||||
start = std::chrono::steady_clock::now();
|
||||
rclcpp::executors::SingleThreadedExecutor client_executor;
|
||||
client_executor.add_node(node);
|
||||
while ((client_cb_count_ < client_qos_profile.depth()) &&
|
||||
(std::chrono::steady_clock::now() - start) < 1s)
|
||||
{
|
||||
client_executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
// Spin an extra time to check if client QoS depth has been ignored,
|
||||
// so more client callbacks might be called than expected.
|
||||
client_executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
|
||||
EXPECT_EQ(client_cb_count_, client_qos_profile.depth());
|
||||
}
|
||||
|
||||
238
rclcpp/test/rclcpp/test_clock.cpp
Normal file
238
rclcpp/test/rclcpp/test_clock.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
// Copyright 2024 Cellumation GmbH
|
||||
//
|
||||
// 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 <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <rcpputils/compile_warnings.hpp>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/time.h"
|
||||
#include "rclcpp/clock.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "rclcpp/time_source.hpp"
|
||||
|
||||
#include "../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class TestClockWakeup : public ::testing::TestWithParam<rcl_clock_type_e>
|
||||
{
|
||||
public:
|
||||
void test_wakeup_before_sleep(const rclcpp::Clock::SharedPtr & clock)
|
||||
{
|
||||
std::atomic_bool thread_finished = false;
|
||||
|
||||
std::thread wait_thread = std::thread(
|
||||
[&clock, &thread_finished]()
|
||||
{
|
||||
// make sure the thread starts sleeping late
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
clock->sleep_until(clock->now() + std::chrono::seconds(3));
|
||||
thread_finished = true;
|
||||
});
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_START
|
||||
// notify the clock, that the sleep shall be interrupted
|
||||
clock->cancel_sleep_or_wait();
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
|
||||
|
||||
auto start_time = std::chrono::steady_clock::now();
|
||||
auto cur_time = start_time;
|
||||
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
cur_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
wait_thread.join();
|
||||
|
||||
EXPECT_TRUE(thread_finished);
|
||||
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
void test_wakeup_after_sleep(const rclcpp::Clock::SharedPtr & clock)
|
||||
{
|
||||
std::atomic_bool thread_finished = false;
|
||||
|
||||
std::thread wait_thread = std::thread(
|
||||
[&clock, &thread_finished]()
|
||||
{
|
||||
clock->sleep_until(clock->now() + std::chrono::seconds(3));
|
||||
thread_finished = true;
|
||||
});
|
||||
|
||||
// make sure the thread is already sleeping before we send the cancel
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_START
|
||||
// notify the clock, that the sleep shall be interrupted
|
||||
clock->cancel_sleep_or_wait();
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
|
||||
|
||||
auto start_time = std::chrono::steady_clock::now();
|
||||
auto cur_time = start_time;
|
||||
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
cur_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
wait_thread.join();
|
||||
|
||||
EXPECT_TRUE(thread_finished);
|
||||
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
void SetUp()
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("my_node");
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
node.reset();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node;
|
||||
};
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
Clocks,
|
||||
TestClockWakeup,
|
||||
::testing::Values(
|
||||
RCL_SYSTEM_TIME, RCL_ROS_TIME, RCL_STEADY_TIME
|
||||
));
|
||||
|
||||
TEST_P(TestClockWakeup, wakeup_sleep) {
|
||||
auto clock = std::make_shared<rclcpp::Clock>(GetParam());
|
||||
test_wakeup_after_sleep(clock);
|
||||
test_wakeup_before_sleep(clock);
|
||||
}
|
||||
|
||||
TEST_F(TestClockWakeup, wakeup_sleep_ros_time_active) {
|
||||
node->set_parameter({"use_sim_time", true});
|
||||
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
|
||||
rclcpp::TimeSource time_source(node);
|
||||
time_source.attachClock(clock);
|
||||
|
||||
EXPECT_TRUE(clock->ros_time_is_active());
|
||||
|
||||
test_wakeup_after_sleep(clock);
|
||||
test_wakeup_before_sleep(clock);
|
||||
}
|
||||
|
||||
TEST_F(TestClockWakeup, no_wakeup_on_sim_time) {
|
||||
node->set_parameter({"use_sim_time", true});
|
||||
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
|
||||
rclcpp::TimeSource time_source(node);
|
||||
time_source.attachClock(clock);
|
||||
|
||||
EXPECT_TRUE(clock->ros_time_is_active());
|
||||
|
||||
std::atomic_bool thread_finished = false;
|
||||
|
||||
std::thread wait_thread = std::thread(
|
||||
[&clock, &thread_finished]()
|
||||
{
|
||||
// make sure the thread starts sleeping late
|
||||
clock->sleep_until(clock->now() + std::chrono::milliseconds(10));
|
||||
thread_finished = true;
|
||||
});
|
||||
|
||||
// make sure, that the sim time clock does not wakeup, as no clock is provided
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
EXPECT_FALSE(thread_finished);
|
||||
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_START
|
||||
// notify the clock, that the sleep shall be interrupted
|
||||
clock->cancel_sleep_or_wait();
|
||||
RCPPUTILS_DEPRECATION_WARNING_OFF_STOP
|
||||
|
||||
auto start_time = std::chrono::steady_clock::now();
|
||||
auto cur_time = start_time;
|
||||
while (!thread_finished && start_time + std::chrono::seconds(1) > cur_time) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
cur_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
wait_thread.join();
|
||||
|
||||
EXPECT_TRUE(thread_finished);
|
||||
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
|
||||
}
|
||||
|
||||
TEST_F(TestClockWakeup, multiple_threads_wait_on_one_clock) {
|
||||
auto clock = std::make_shared<rclcpp::Clock>(RCL_ROS_TIME);
|
||||
|
||||
std::vector<std::atomic_bool> thread_finished(10);
|
||||
for (std::atomic_bool & finished : thread_finished) {
|
||||
finished = false;
|
||||
}
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for (size_t nr = 0; nr < thread_finished.size(); nr++) {
|
||||
threads.push_back(
|
||||
std::thread(
|
||||
[&clock, &thread_finished, nr]()
|
||||
{
|
||||
// make sure the thread starts sleeping late
|
||||
clock->sleep_until(clock->now() + std::chrono::seconds(10));
|
||||
thread_finished[nr] = true;
|
||||
}));
|
||||
}
|
||||
|
||||
// wait a bit so all threads can execute the sleep_until
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
|
||||
for (const std::atomic_bool & finished : thread_finished) {
|
||||
EXPECT_FALSE(finished);
|
||||
}
|
||||
|
||||
rclcpp::shutdown();
|
||||
|
||||
auto start_time = std::chrono::steady_clock::now();
|
||||
auto cur_time = start_time;
|
||||
bool threads_finished = false;
|
||||
while (!threads_finished && start_time + std::chrono::seconds(1) > cur_time) {
|
||||
threads_finished = true;
|
||||
for (const std::atomic_bool & finished : thread_finished) {
|
||||
if (!finished) {
|
||||
threads_finished = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
cur_time = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
for (const std::atomic_bool & finished : thread_finished) {
|
||||
EXPECT_TRUE(finished);
|
||||
}
|
||||
|
||||
for (auto & thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
|
||||
EXPECT_LT(cur_time, start_time + std::chrono::seconds(1));
|
||||
}
|
||||
@@ -42,9 +42,7 @@ TEST(TestCreateTimer, timer_executes)
|
||||
timer->cancel();
|
||||
});
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
|
||||
ASSERT_TRUE(got_callback);
|
||||
rclcpp::shutdown();
|
||||
|
||||
@@ -15,20 +15,17 @@
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
#include "test_msgs/message_fixtures.hpp"
|
||||
#include "test_msgs/msg/basic_types.hpp"
|
||||
|
||||
#include "rcl/graph.h"
|
||||
|
||||
#include "rclcpp/executors/single_threaded_executor.hpp"
|
||||
#include "rclcpp/generic_publisher.hpp"
|
||||
#include "rclcpp/generic_subscription.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
@@ -37,7 +34,6 @@
|
||||
|
||||
using namespace ::testing; // NOLINT
|
||||
using namespace rclcpp; // NOLINT
|
||||
using namespace std::chrono_literals; // NOLINT
|
||||
|
||||
class RclcppGenericNodeFixture : public Test
|
||||
{
|
||||
@@ -82,10 +78,8 @@ public:
|
||||
counter++;
|
||||
});
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node_);
|
||||
while (counter < expected_recv_msg_count) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node_);
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
@@ -113,13 +107,11 @@ public:
|
||||
{
|
||||
using clock = std::chrono::system_clock;
|
||||
auto start = clock::now();
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node_);
|
||||
while (!condition()) {
|
||||
if ((clock::now() - start) > timeout) {
|
||||
return false;
|
||||
}
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node_);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -318,133 +310,3 @@ TEST_F(RclcppGenericNodeFixture, generic_subscription_different_callbacks)
|
||||
ASSERT_TRUE(wait_for(connected, 5s));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RclcppGenericNodeFixture, disable_enable_subscription_callbacks)
|
||||
{
|
||||
const std::string topic_name = "test_disable_topic";
|
||||
const std::string type = "test_msgs/msg/Strings";
|
||||
const auto qos = rclcpp::QoS(10U);
|
||||
|
||||
std::atomic<int> callback_count{0};
|
||||
auto callback = [&callback_count](std::shared_ptr<const rclcpp::SerializedMessage>) {
|
||||
++callback_count;
|
||||
};
|
||||
|
||||
auto subscription = node_->create_generic_subscription(topic_name, type, qos, callback);
|
||||
auto publisher = node_->create_generic_publisher(topic_name, type, qos);
|
||||
|
||||
// Wait for discovery
|
||||
auto connected = [publisher, subscription]() -> bool {
|
||||
return publisher->get_subscription_count() && subscription->get_publisher_count();
|
||||
};
|
||||
ASSERT_TRUE(wait_for(connected, 10s));
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node_);
|
||||
|
||||
// Publish and verify callback is called
|
||||
publisher->publish(serialize_message<std::string, test_msgs::msg::Strings>("test1"));
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (callback_count.load() == 0 && std::chrono::steady_clock::now() - start < 30s) {
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Disable callbacks
|
||||
EXPECT_NO_THROW(subscription->disable_callbacks());
|
||||
|
||||
// Publish again and verify callback is NOT called
|
||||
publisher->publish(serialize_message<std::string, test_msgs::msg::Strings>("test2"));
|
||||
|
||||
start = std::chrono::steady_clock::now();
|
||||
auto initial_count = callback_count.load();
|
||||
while (std::chrono::steady_clock::now() - start < 500ms) {
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
EXPECT_EQ(initial_count, callback_count.load()); // Should not increase
|
||||
|
||||
// Enable callbacks
|
||||
EXPECT_NO_THROW(subscription->enable_callbacks());
|
||||
|
||||
// Publish again and verify callback IS called
|
||||
publisher->publish(serialize_message<std::string, test_msgs::msg::Strings>("test3"));
|
||||
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (callback_count.load() == initial_count && std::chrono::steady_clock::now() - start < 30s) {
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
EXPECT_EQ(callback_count.load(), initial_count + 1);
|
||||
}
|
||||
|
||||
TEST_F(RclcppGenericNodeFixture, disable_enable_subscription_event_callbacks)
|
||||
{
|
||||
if (std::string(rmw_get_implementation_identifier()).find("rmw_zenoh_cpp") == 0) {
|
||||
GTEST_SKIP() << "rmw_zenoh doesn't support deadline and liveliness events";
|
||||
}
|
||||
const std::string topic_name = "test_event_callbacks_topic";
|
||||
const std::string type = "test_msgs/msg/Strings";
|
||||
const auto qos = rclcpp::QoS(10U).deadline(100ms);
|
||||
|
||||
std::atomic<int> deadline_callback_count{0};
|
||||
std::atomic<int> liveliness_callback_count{0};
|
||||
|
||||
rclcpp::SubscriptionOptions sub_options;
|
||||
sub_options.event_callbacks.deadline_callback =
|
||||
[&deadline_callback_count](rclcpp::QOSDeadlineRequestedInfo &) {
|
||||
++deadline_callback_count;
|
||||
};
|
||||
|
||||
sub_options.event_callbacks.liveliness_callback =
|
||||
[&liveliness_callback_count](rclcpp::QOSLivelinessChangedInfo &) {
|
||||
++liveliness_callback_count;
|
||||
};
|
||||
|
||||
auto do_nothing = [](std::shared_ptr<const rclcpp::SerializedMessage>) {};
|
||||
|
||||
auto subscription =
|
||||
node_->create_generic_subscription(topic_name, type, qos, do_nothing, sub_options);
|
||||
|
||||
const auto & event_handlers = subscription->get_event_handlers();
|
||||
|
||||
// Initially, both callbacks counters should be zero
|
||||
EXPECT_EQ(deadline_callback_count, 0);
|
||||
EXPECT_EQ(liveliness_callback_count, 0);
|
||||
|
||||
// Execute events and disable all event handlers
|
||||
for (const auto & [event_type, handler] : event_handlers) {
|
||||
if (handler) {
|
||||
const std::shared_ptr<void> data = handler->take_data();
|
||||
handler->execute(data);
|
||||
EXPECT_NO_THROW(handler->disable());
|
||||
}
|
||||
}
|
||||
// Expect both callbacks to have been called once since they should be enabled by default
|
||||
EXPECT_EQ(deadline_callback_count, 1);
|
||||
EXPECT_EQ(liveliness_callback_count, 1);
|
||||
|
||||
// Execute events one more time and enable all event handlers
|
||||
for (const auto & [event_type, handler] : event_handlers) {
|
||||
if (handler) {
|
||||
const std::shared_ptr<void> data = handler->take_data();
|
||||
handler->execute(data);
|
||||
EXPECT_NO_THROW(handler->enable());
|
||||
}
|
||||
}
|
||||
// Expect no change since they were disabled
|
||||
EXPECT_EQ(deadline_callback_count, 1);
|
||||
EXPECT_EQ(liveliness_callback_count, 1);
|
||||
|
||||
// Execute events one more time
|
||||
for (const auto & [event_type, handler] : event_handlers) {
|
||||
if (handler) {
|
||||
const std::shared_ptr<void> data = handler->take_data();
|
||||
handler->execute(data);
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(deadline_callback_count, 2);
|
||||
EXPECT_EQ(liveliness_callback_count, 2);
|
||||
}
|
||||
|
||||
@@ -372,18 +372,16 @@ TEST_F(TestGenericService, generic_service_qos_depth) {
|
||||
}
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(server_node);
|
||||
while ((server_cb_count_ < server_qos_profile.depth()) &&
|
||||
(std::chrono::steady_clock::now() - start) < 1s)
|
||||
{
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(server_node);
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
|
||||
// Spin an extra time to check if server QoS depth has been ignored,
|
||||
// so more server responses might be processed than expected.
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(server_node);
|
||||
|
||||
EXPECT_EQ(server_cb_count_, server_qos_profile.depth());
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@ public:
|
||||
node_graph_ = node_->get_node_graph_interface();
|
||||
ASSERT_NE(nullptr, node_graph_);
|
||||
|
||||
graph_listener_ = rclcpp::contexts::get_global_default_context()->get_graph_listener();
|
||||
graph_listener_ =
|
||||
std::make_shared<rclcpp::graph_listener::GraphListener>(
|
||||
rclcpp::contexts::get_global_default_context());
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
/*
|
||||
Constructor
|
||||
Construtctor
|
||||
*/
|
||||
TEST(TestIntraProcessBuffer, constructor) {
|
||||
using MessageT = char;
|
||||
|
||||
@@ -129,8 +129,6 @@ TEST_F(TestMemoryStrategy, get_subscription_by_handle) {
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
memory_strategy()->get_subscription_by_handle(subscription_handle, weak_groups_to_nodes));
|
||||
// Clear all handles to cleanup when node is destroyed
|
||||
memory_strategy()->clear_handles();
|
||||
} // Node goes out of scope
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
@@ -183,8 +181,6 @@ TEST_F(TestMemoryStrategy, get_service_by_handle) {
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
memory_strategy()->get_service_by_handle(service_handle, weak_groups_to_nodes));
|
||||
// Clear all handles to cleanup when node is destroyed
|
||||
memory_strategy()->clear_handles();
|
||||
} // Node goes out of scope
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
@@ -232,11 +228,6 @@ TEST_F(TestMemoryStrategy, get_client_by_handle) {
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
memory_strategy()->get_client_by_handle(client_handle, weak_groups_to_nodes));
|
||||
// Clear all handles to cleanup when node is destroyed
|
||||
memory_strategy()->clear_handles();
|
||||
// reset client handle before node destruction, otherwise it tries to access node
|
||||
// via weak_ptr in its deleter
|
||||
client_handle.reset();
|
||||
} // Node goes out of scope
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
@@ -285,8 +276,6 @@ TEST_F(TestMemoryStrategy, get_timer_by_handle) {
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
memory_strategy()->get_timer_by_handle(timer_handle, weak_groups_to_nodes));
|
||||
// Clear all handles to cleanup when node is destroyed
|
||||
memory_strategy()->clear_handles();
|
||||
} // Node goes out of scope
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
@@ -386,8 +375,6 @@ TEST_F(TestMemoryStrategy, get_group_by_subscription) {
|
||||
EXPECT_EQ(
|
||||
callback_group,
|
||||
memory_strategy()->get_group_by_subscription(subscription, weak_groups_to_nodes));
|
||||
// Clear all handles to cleanup when node is destroyed
|
||||
memory_strategy()->clear_handles();
|
||||
} // Node goes out of scope
|
||||
// NodeBase(SubscriptionBase->rcl_node_t->NodeBase) is still alive.
|
||||
EXPECT_EQ(
|
||||
@@ -433,8 +420,6 @@ TEST_F(TestMemoryStrategy, get_group_by_service) {
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
memory_strategy()->get_group_by_service(service, weak_groups_to_nodes));
|
||||
// Clear all handles to cleanup when node is destroyed
|
||||
memory_strategy()->clear_handles();
|
||||
} // Node goes out of scope
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
@@ -474,8 +459,6 @@ TEST_F(TestMemoryStrategy, get_group_by_client) {
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
memory_strategy()->get_group_by_client(client, weak_groups_to_nodes));
|
||||
// Clear all handles to cleanup when node is destroyed
|
||||
memory_strategy()->clear_handles();
|
||||
} // Node goes out of scope
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
@@ -515,8 +498,6 @@ TEST_F(TestMemoryStrategy, get_group_by_timer) {
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
memory_strategy()->get_group_by_timer(timer, weak_groups_to_nodes));
|
||||
// Clear all handles to cleanup when node is destroyed
|
||||
memory_strategy()->clear_handles();
|
||||
} // Node goes out of scope
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
@@ -555,8 +536,6 @@ TEST_F(TestMemoryStrategy, get_group_by_waitable) {
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
memory_strategy()->get_group_by_waitable(waitable, weak_groups_to_nodes));
|
||||
// Clear all handles to cleanup when node is destroyed
|
||||
memory_strategy()->clear_handles();
|
||||
} // Node goes out of scope
|
||||
EXPECT_EQ(
|
||||
nullptr,
|
||||
|
||||
@@ -1365,203 +1365,6 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_not_allowed) {
|
||||
node->declare_parameter(name, 42, descriptor),
|
||||
rclcpp::exceptions::InvalidParameterValueException);
|
||||
}
|
||||
{
|
||||
// setting an array parameter with integer range descriptor
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 10;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 2;
|
||||
node->declare_parameter(name, std::vector<int64_t>{10, 12, 14, 16, 18}, descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({10, 12, 14, 16, 18}));
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({12, 14, 10}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({12, 14, 10}));
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({10, 10, 10}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({10, 10, 10}));
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({18}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({15}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({20}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({8}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({12, 8, 18}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with integer range descriptor, from_value > to_value
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 20;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 1;
|
||||
node->declare_parameter(name, std::vector<int64_t>({18, 20}), descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18, 20}));
|
||||
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({20, 18}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({20, 18}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({18, 19, 20}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({20, 18}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({10}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({20, 18}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({25}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({20, 18}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with integer range descriptor, from_value = to_value
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 18;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 1;
|
||||
node->declare_parameter(name, std::vector<int64_t>({18}), descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({17}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({19}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with integer range descriptor,
|
||||
// step > distance(from_value, to_value)
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 18;
|
||||
integer_range.to_value = 25;
|
||||
integer_range.step = 10;
|
||||
node->declare_parameter(name, std::vector<int64_t>({18, 25}), descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18, 25}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({17}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18, 25}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({19}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18, 25}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({28}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18, 25}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with integer range descriptor, distance not multiple of the step.
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 18;
|
||||
integer_range.to_value = 28;
|
||||
integer_range.step = 7;
|
||||
node->declare_parameter(name, std::vector<int64_t>({18, 25, 28}), descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<int64_t>>(), std::vector<int64_t>({18, 25, 28}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({17}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18, 25, 28}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({19}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18, 25, 28}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({32}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({18, 25, 28}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with integer range descriptor, step=0
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 10;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 0;
|
||||
node->declare_parameter(name, std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}),
|
||||
descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({9}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<int64_t>({19}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<int64_t>>(),
|
||||
std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with integer range descriptor and wrong default value will throw
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.integer_range.resize(1);
|
||||
auto & integer_range = descriptor.integer_range.at(0);
|
||||
integer_range.from_value = 10;
|
||||
integer_range.to_value = 18;
|
||||
integer_range.step = 2;
|
||||
ASSERT_THROW(
|
||||
node->declare_parameter(name, std::vector<int64_t>({10, 11, 12, 13, 14, 15, 16, 17, 18}),
|
||||
descriptor),
|
||||
rclcpp::exceptions::InvalidParameterValueException);
|
||||
}
|
||||
{
|
||||
// setting a parameter with floating point range descriptor
|
||||
auto name = "parameter"_unq;
|
||||
@@ -1732,201 +1535,6 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_not_allowed) {
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name, 9.999)).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<double>(), 11.0);
|
||||
}
|
||||
{
|
||||
// setting an array parameter with floating point range descriptor
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = 0.2;
|
||||
node->declare_parameter(name, std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}),
|
||||
descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({10.3}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({12.0}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({9.4}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.4, 11.0, 10.8, 10.2, 10.6}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with floating point range descriptor, negative step
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = -0.2;
|
||||
node->declare_parameter(name, std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}),
|
||||
descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({10.3}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({12.0}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({9.4}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.2, 10.4, 10.6, 10.8, 11.0}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with floating point range descriptor, from_value > to_value
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 11.0;
|
||||
floating_point_range.to_value = 10.0;
|
||||
floating_point_range.step = 0.2;
|
||||
node->declare_parameter(name, std::vector<double>({10.0, 11.0}), descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0, 11.0}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({10.2}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 11.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({12.0}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 11.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({9.4}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 11.0}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with floating point range descriptor, from_value = to_value
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 10.0;
|
||||
floating_point_range.step = 0.2;
|
||||
node->declare_parameter(name, std::vector<double>({10.0}), descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({11.2}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({12.0}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({9.4}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with floating point range descriptor, step > distance
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = 2.2;
|
||||
node->declare_parameter(name, std::vector<double>({10.0, 11.0}), descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0, 11.0}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({12.2}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 11.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({7.8}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 11.0}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with floating point range descriptor,
|
||||
// distance not multiple of the step.
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = 0.7;
|
||||
node->declare_parameter(name, std::vector<double>({10.0, 10.7, 11.0}), descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<double>>(), std::vector<double>({10.0, 10.7, 11.0}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({12.2}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.7, 11.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({11.4}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.7, 11.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({9.3}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.7, 11.0}));
|
||||
}
|
||||
{
|
||||
// setting an array parameter with floating point range descriptor, step=0
|
||||
auto name = "parameter"_unq;
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.floating_point_range.resize(1);
|
||||
auto & floating_point_range = descriptor.floating_point_range.at(0);
|
||||
floating_point_range.from_value = 10.0;
|
||||
floating_point_range.to_value = 11.0;
|
||||
floating_point_range.step = 0.0;
|
||||
node->declare_parameter(name, std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}),
|
||||
descriptor);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
auto value = node->get_parameter(name);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
|
||||
EXPECT_EQ(value.get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}));
|
||||
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({11.001}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}));
|
||||
EXPECT_FALSE(node->set_parameter(rclcpp::Parameter(name,
|
||||
std::vector<double>({9.999}))).successful);
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<std::vector<double>>(),
|
||||
std::vector<double>({10.0, 10.0001, 10.5479051, 11.0}));
|
||||
}
|
||||
{
|
||||
// setting a parameter with a different type is still possible
|
||||
// when having a descriptor specifying a type (type is a status, not a constraint).
|
||||
@@ -3689,115 +3297,6 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
|
||||
// test that calling get_clients_info_by_service and get_servers_info_by_service
|
||||
TEST_F(TestNode, get_clients_servers_info_by_service) {
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
std::string service_name = "test_service_info";
|
||||
std::string fq_service_name = rclcpp::expand_topic_or_service_name(
|
||||
service_name, node->get_name(), node->get_namespace(), true);
|
||||
|
||||
// Lists should be empty
|
||||
EXPECT_TRUE(node->get_clients_info_by_service(fq_service_name).empty());
|
||||
EXPECT_TRUE(node->get_servers_info_by_service(fq_service_name).empty());
|
||||
|
||||
// Add a client
|
||||
rclcpp::QoSInitialization qos_initialization =
|
||||
{
|
||||
RMW_QOS_POLICY_HISTORY_KEEP_ALL,
|
||||
10
|
||||
};
|
||||
rmw_qos_profile_t rmw_qos_profile_default =
|
||||
{
|
||||
RMW_QOS_POLICY_HISTORY_KEEP_ALL,
|
||||
10,
|
||||
RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
|
||||
RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
|
||||
{1, 12345},
|
||||
{20, 9887665},
|
||||
RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC,
|
||||
{5, 23456},
|
||||
false
|
||||
};
|
||||
rclcpp::QoS qos = rclcpp::QoS(qos_initialization, rmw_qos_profile_default);
|
||||
auto client = node->create_client<test_msgs::srv::Empty>(service_name, qos);
|
||||
|
||||
// Wait for the underlying RMW implementation to catch up with graph changes
|
||||
auto client_is_generated =
|
||||
[&]() {return node->get_clients_info_by_service(fq_service_name).size() == 1u;};
|
||||
ASSERT_TRUE(wait_for_event(node, client_is_generated));
|
||||
|
||||
// List should have one item
|
||||
auto clients_info = node->get_clients_info_by_service(fq_service_name);
|
||||
ASSERT_EQ(clients_info.size(), (size_t) 1);
|
||||
// Server list should be empty
|
||||
EXPECT_TRUE(node->get_servers_info_by_service(fq_service_name).empty());
|
||||
|
||||
// Verify client info has the right data.
|
||||
EXPECT_EQ(node->get_name(), clients_info[0].node_name());
|
||||
EXPECT_EQ(node->get_namespace(), clients_info[0].node_namespace());
|
||||
EXPECT_EQ("test_msgs/srv/Empty", clients_info[0].service_type());
|
||||
EXPECT_EQ(rclcpp::EndpointType::Client, clients_info[0].endpoint_type());
|
||||
EXPECT_TRUE(clients_info[0].endpoint_count() == 1 || clients_info[0].endpoint_count() == 2);
|
||||
for(size_t i = 0; i < clients_info[0].endpoint_count(); i++) {
|
||||
auto qos_profile = clients_info[0].qos_profiles()[i].get_rmw_qos_profile();
|
||||
expect_qos_profile_eq(qos.get_rmw_qos_profile(), qos_profile, false);
|
||||
}
|
||||
|
||||
// Add a service server
|
||||
rclcpp::QoSInitialization qos_initialization2 =
|
||||
{
|
||||
RMW_QOS_POLICY_HISTORY_KEEP_LAST,
|
||||
0
|
||||
};
|
||||
rmw_qos_profile_t rmw_qos_profile_default2 =
|
||||
{
|
||||
RMW_QOS_POLICY_HISTORY_KEEP_LAST,
|
||||
0,
|
||||
RMW_QOS_POLICY_RELIABILITY_RELIABLE,
|
||||
RMW_QOS_POLICY_DURABILITY_VOLATILE,
|
||||
{15, 1678},
|
||||
{29, 2345},
|
||||
RMW_QOS_POLICY_LIVELINESS_AUTOMATIC,
|
||||
{5, 23456},
|
||||
false
|
||||
};
|
||||
rclcpp::QoS qos2 = rclcpp::QoS(qos_initialization2, rmw_qos_profile_default2);
|
||||
auto callback = [](test_msgs::srv::Empty_Request::ConstSharedPtr req,
|
||||
test_msgs::srv::Empty_Response::ConstSharedPtr resp) {
|
||||
(void)req;
|
||||
(void)resp;
|
||||
};
|
||||
auto server = node->create_service<test_msgs::srv::Empty>(service_name, callback, qos2);
|
||||
// Wait for the underlying RMW implementation to catch up with graph changes
|
||||
auto server_is_generated =
|
||||
[&]() {return node->get_servers_info_by_service(fq_service_name).size() == 1u;};
|
||||
ASSERT_TRUE(wait_for_event(node, server_is_generated));
|
||||
|
||||
// List should have one item
|
||||
auto servers_info = node->get_servers_info_by_service(fq_service_name);
|
||||
ASSERT_EQ(servers_info.size(), (size_t) 1);
|
||||
// Verify server info has the right data.
|
||||
EXPECT_EQ(node->get_name(), servers_info[0].node_name());
|
||||
EXPECT_EQ(node->get_namespace(), servers_info[0].node_namespace());
|
||||
EXPECT_EQ("test_msgs/srv/Empty", servers_info[0].service_type());
|
||||
EXPECT_EQ(rclcpp::EndpointType::Server, servers_info[0].endpoint_type());
|
||||
EXPECT_TRUE(servers_info[0].endpoint_count() == 1 || servers_info[0].endpoint_count() == 2);
|
||||
for(size_t i = 0; i < servers_info[0].endpoint_count(); i++) {
|
||||
auto qos_profile = servers_info[0].qos_profiles()[i].get_rmw_qos_profile();
|
||||
expect_qos_profile_eq(qos2.get_rmw_qos_profile(), qos_profile, false);
|
||||
}
|
||||
|
||||
// Error cases
|
||||
EXPECT_THROW(
|
||||
{
|
||||
clients_info = node->get_clients_info_by_service("13");
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
EXPECT_THROW(
|
||||
{
|
||||
servers_info = node->get_servers_info_by_service("13");
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
|
||||
TEST_F(TestNode, callback_groups) {
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
size_t num_callback_groups_in_basic_node = 0;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -21,8 +20,6 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class TestParameterEventHandler : public rclcpp::ParameterEventHandler
|
||||
{
|
||||
public:
|
||||
@@ -446,199 +443,3 @@ TEST_F(TestNode, LastInFirstCallForParameterEventCallbacks)
|
||||
param_handler->remove_parameter_event_callback(h2);
|
||||
EXPECT_EQ(param_handler->num_event_callbacks(), 0UL);
|
||||
}
|
||||
|
||||
TEST_F(TestNode, ConfigureNodesFilterAndCheckAddParameterEventCallback)
|
||||
{
|
||||
std::string rmw_implementation_str = std::string(rmw_get_implementation_identifier());
|
||||
if (rmw_implementation_str != "rmw_fastrtps_cpp" && rmw_implementation_str != "rmw_connextdds") {
|
||||
GTEST_SKIP() << "Content filter is now only supported in FastDDS and ConnextDDS.";
|
||||
}
|
||||
|
||||
const std::string remote_node_name1 = "remote_node1";
|
||||
const std::string remote_node_name2 = "remote_node2";
|
||||
rclcpp::NodeOptions options;
|
||||
options.enable_rosout(false);
|
||||
auto remote_node1 = std::make_shared<rclcpp::Node>(
|
||||
remote_node_name1, options);
|
||||
auto remote_node2 = std::make_shared<rclcpp::Node>(
|
||||
remote_node_name2, options);
|
||||
|
||||
const std::string remote_node1_param_name = "param_node1";
|
||||
const std::string remote_node2_param_name = "param_node2";
|
||||
remote_node1->declare_parameter(remote_node1_param_name, 10);
|
||||
remote_node2->declare_parameter(remote_node2_param_name, "Default");
|
||||
|
||||
std::atomic_bool received_from_remote_node1{false};
|
||||
std::atomic_bool received_from_remote_node2{false};
|
||||
|
||||
auto cb =
|
||||
[&remote_node_name1, &remote_node_name2, &received_from_remote_node1,
|
||||
&received_from_remote_node2]
|
||||
(const rcl_interfaces::msg::ParameterEvent & parm) {
|
||||
if (parm.node == "/" + remote_node_name1) {
|
||||
received_from_remote_node1 = true;
|
||||
} else if (parm.node == "/" + remote_node_name2) {
|
||||
received_from_remote_node2 = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Configure to only receive parameter events from remote_node_name2
|
||||
ASSERT_TRUE(param_handler->configure_nodes_filter({remote_node_name2}));
|
||||
|
||||
auto handler = param_handler->add_parameter_event_callback(cb);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
executor.add_node(remote_node1);
|
||||
executor.add_node(remote_node2);
|
||||
|
||||
auto wait_param_event = [&executor]
|
||||
(std::chrono::seconds timeout, std::function<bool()> condition = nullptr) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (std::chrono::steady_clock::now() - start < timeout) {
|
||||
executor.spin_some();
|
||||
if (condition && condition()) {
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
std::thread thread(wait_param_event, 1s, nullptr);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
remote_node1->set_parameter(rclcpp::Parameter(remote_node1_param_name, 20));
|
||||
remote_node2->set_parameter(rclcpp::Parameter(remote_node2_param_name, "abc"));
|
||||
thread.join();
|
||||
}
|
||||
|
||||
EXPECT_EQ(received_from_remote_node1, false);
|
||||
EXPECT_EQ(received_from_remote_node2, true);
|
||||
|
||||
// Clear node filter and all parameter events from remote nodes should be received
|
||||
ASSERT_TRUE(param_handler->configure_nodes_filter({}));
|
||||
|
||||
received_from_remote_node1 = false;
|
||||
received_from_remote_node2 = false;
|
||||
|
||||
{
|
||||
std::thread thread(
|
||||
wait_param_event,
|
||||
2s,
|
||||
[&received_from_remote_node1, &received_from_remote_node2]() {
|
||||
if (received_from_remote_node1 && received_from_remote_node2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
std::this_thread::sleep_for(100ms);
|
||||
remote_node1->set_parameter(rclcpp::Parameter(remote_node1_param_name, 30));
|
||||
remote_node2->set_parameter(rclcpp::Parameter(remote_node2_param_name, "def"));
|
||||
thread.join();
|
||||
}
|
||||
|
||||
EXPECT_EQ(received_from_remote_node1, true);
|
||||
EXPECT_EQ(received_from_remote_node2, true);
|
||||
}
|
||||
|
||||
TEST_F(TestNode, ConfigureNodesFilterAndCheckAddParameterCallback)
|
||||
{
|
||||
std::string rmw_implementation_str = std::string(rmw_get_implementation_identifier());
|
||||
if (rmw_implementation_str != "rmw_fastrtps_cpp" && rmw_implementation_str != "rmw_connextdds") {
|
||||
GTEST_SKIP() << "Content filter is now only supported in FastDDS and ConnextDDS.";
|
||||
}
|
||||
|
||||
const std::string remote_node_name1 = "remote_node1";
|
||||
const std::string remote_node_name2 = "remote_node2";
|
||||
rclcpp::NodeOptions options;
|
||||
options.enable_rosout(false);
|
||||
auto remote_node1 = std::make_shared<rclcpp::Node>(
|
||||
remote_node_name1, options);
|
||||
auto remote_node2 = std::make_shared<rclcpp::Node>(
|
||||
remote_node_name2, options);
|
||||
|
||||
const std::string remote_node1_param_name = "param_node1";
|
||||
const std::string remote_node2_param_name = "param_node2";
|
||||
remote_node1->declare_parameter(remote_node1_param_name, 10);
|
||||
remote_node2->declare_parameter(remote_node2_param_name, "Default");
|
||||
|
||||
std::atomic_bool received_from_remote_node1{false};
|
||||
std::atomic_bool received_from_remote_node2{false};
|
||||
|
||||
auto cb_remote_node1 =
|
||||
[&remote_node1_param_name, &received_from_remote_node1]
|
||||
(const rclcpp::Parameter & parm) {
|
||||
if (parm.get_name() == remote_node1_param_name) {
|
||||
received_from_remote_node1 = true;
|
||||
}
|
||||
};
|
||||
|
||||
auto cb_remote_node2 =
|
||||
[&remote_node2_param_name, &received_from_remote_node2]
|
||||
(const rclcpp::Parameter & parm) {
|
||||
if (parm.get_name() == remote_node2_param_name) {
|
||||
received_from_remote_node2 = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Configure to only receive parameter events from remote_node_name2
|
||||
ASSERT_TRUE(param_handler->configure_nodes_filter({remote_node_name2}));
|
||||
|
||||
auto handler1 = param_handler->add_parameter_callback(
|
||||
remote_node1_param_name, cb_remote_node1, remote_node_name1);
|
||||
auto handler2 = param_handler->add_parameter_callback(
|
||||
remote_node2_param_name, cb_remote_node2, remote_node_name2);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
executor.add_node(remote_node1);
|
||||
executor.add_node(remote_node2);
|
||||
|
||||
auto wait_param_event = [&executor]
|
||||
(std::chrono::seconds timeout, std::function<bool()> condition = nullptr) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (std::chrono::steady_clock::now() - start < timeout) {
|
||||
executor.spin_some();
|
||||
if (condition && condition()) {
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
std::thread thread(wait_param_event, 1s, nullptr);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
remote_node1->set_parameter(rclcpp::Parameter(remote_node1_param_name, 20));
|
||||
remote_node2->set_parameter(rclcpp::Parameter(remote_node2_param_name, "abc"));
|
||||
thread.join();
|
||||
}
|
||||
|
||||
EXPECT_EQ(received_from_remote_node1, false);
|
||||
EXPECT_EQ(received_from_remote_node2, true);
|
||||
|
||||
// Clear node filter and all parameter events from remote nodes should be received
|
||||
ASSERT_TRUE(param_handler->configure_nodes_filter({}));
|
||||
|
||||
received_from_remote_node1 = false;
|
||||
received_from_remote_node2 = false;
|
||||
|
||||
{
|
||||
std::thread thread(
|
||||
wait_param_event,
|
||||
2s,
|
||||
[&received_from_remote_node1, &received_from_remote_node2]() {
|
||||
if (received_from_remote_node1 && received_from_remote_node2) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
std::this_thread::sleep_for(100ms);
|
||||
remote_node1->set_parameter(rclcpp::Parameter(remote_node1_param_name, 30));
|
||||
remote_node2->set_parameter(rclcpp::Parameter(remote_node2_param_name, "def"));
|
||||
thread.join();
|
||||
}
|
||||
|
||||
EXPECT_EQ(received_from_remote_node1, true);
|
||||
EXPECT_EQ(received_from_remote_node2, true);
|
||||
}
|
||||
|
||||
@@ -120,32 +120,3 @@ TEST_F(TestParameterService, describe_parameters) {
|
||||
EXPECT_EQ(0u, parameter_descs.size());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestParameterService, parameter_descriptor) {
|
||||
{
|
||||
rclcpp::ParameterDescription param_description;
|
||||
rclcpp::ParameterValue param_value(1);
|
||||
|
||||
param_description.set_name("int_parameter");
|
||||
param_description.set_type(2);
|
||||
param_description.set_description_text("description");
|
||||
param_description.set_additional_constraints("constraints");
|
||||
param_description.set_read_only(false);
|
||||
param_description.set_integer_description_range(0, 10, 1);
|
||||
|
||||
auto param = param_description.build();
|
||||
param_description.declare_parameter(param_value, node);
|
||||
|
||||
EXPECT_EQ("int_parameter", param.name);
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, param.type);
|
||||
EXPECT_EQ("description", param.description);
|
||||
EXPECT_EQ("constraints", param.additional_constraints);
|
||||
EXPECT_EQ(0u, param.read_only);
|
||||
EXPECT_EQ(0u, param.dynamic_typing);
|
||||
EXPECT_EQ(0u, param.integer_range.at(0).from_value);
|
||||
EXPECT_EQ(10, param.integer_range.at(0).to_value);
|
||||
EXPECT_EQ(1, param.integer_range.at(0).step);
|
||||
|
||||
ASSERT_EQ(1, client->get_parameter("int_parameter", 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,18 +219,6 @@ TEST(TestQoS, policy_name_from_kind) {
|
||||
EXPECT_EQ(
|
||||
"LIFESPAN_QOS_POLICY",
|
||||
rclcpp::qos_policy_name_from_kind(RMW_QOS_POLICY_LIFESPAN));
|
||||
|
||||
EXPECT_EQ(
|
||||
"DEPTH_QOS_POLICY",
|
||||
rclcpp::qos_policy_name_from_kind(RMW_QOS_POLICY_DEPTH));
|
||||
|
||||
EXPECT_EQ(
|
||||
"LIVELINESS_LEASE_DURATION_QOS_POLICY",
|
||||
rclcpp::qos_policy_name_from_kind(RMW_QOS_POLICY_LIVELINESS_LEASE_DURATION));
|
||||
|
||||
EXPECT_EQ(
|
||||
"AVOID_ROS_NAMESPACE_CONVENTIONS_QOS_POLICY",
|
||||
rclcpp::qos_policy_name_from_kind(RMW_QOS_POLICY_AVOID_ROS_NAMESPACE_CONVENTIONS));
|
||||
}
|
||||
|
||||
TEST(TestQoS, qos_check_compatible)
|
||||
|
||||
@@ -173,12 +173,3 @@ TEST_F(TestRate, incorrect_constuctor) {
|
||||
rclcpp::Rate rate(rclcpp::Duration(-1, 0)),
|
||||
std::invalid_argument("period must be greater than 0"));
|
||||
}
|
||||
|
||||
TEST(TestRateBasic, invalid_context) {
|
||||
rclcpp::init(0, nullptr);
|
||||
rclcpp::Rate rate(1.0);
|
||||
ASSERT_TRUE(rate.sleep());
|
||||
rclcpp::shutdown();
|
||||
EXPECT_NO_THROW(rate.sleep());
|
||||
ASSERT_FALSE(rate.sleep());
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "rclcpp/experimental/buffers/ring_buffer_implementation.hpp"
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
* Construtctor
|
||||
*/
|
||||
TEST(TestRingBufferImplementation, constructor) {
|
||||
// Cannot create a buffer of size zero.
|
||||
@@ -140,31 +140,6 @@ TEST(TestRingBufferImplementation, basic_usage_unique_ptr) {
|
||||
EXPECT_EQ(false, rb.is_full());
|
||||
}
|
||||
|
||||
TEST(TestRingBufferImplementation, test_buffer_clear) {
|
||||
rclcpp::experimental::buffers::RingBufferImplementation<char> rb(2);
|
||||
rb.enqueue('a');
|
||||
rb.enqueue('b');
|
||||
|
||||
EXPECT_EQ(true, rb.has_data());
|
||||
EXPECT_EQ(true, rb.is_full());
|
||||
const auto all_data_vec = rb.get_all_data();
|
||||
EXPECT_EQ(2u, all_data_vec.capacity());
|
||||
EXPECT_EQ(2u, all_data_vec.size());
|
||||
rb.clear();
|
||||
EXPECT_EQ(false, rb.has_data());
|
||||
EXPECT_EQ(false, rb.is_full());
|
||||
const auto all_data_vec_empty = rb.get_all_data();
|
||||
EXPECT_EQ(0u, all_data_vec_empty.capacity());
|
||||
EXPECT_EQ(0u, all_data_vec_empty.size());
|
||||
rb.enqueue('c');
|
||||
rb.enqueue('d');
|
||||
const auto c = rb.dequeue();
|
||||
const auto d = rb.dequeue();
|
||||
|
||||
EXPECT_EQ('c', c);
|
||||
EXPECT_EQ('d', d);
|
||||
}
|
||||
|
||||
TEST(TestRingBufferImplementation, handle_nullptr_deletion) {
|
||||
rclcpp::experimental::buffers::RingBufferImplementation<std::unique_ptr<int>> rb(3);
|
||||
rb.enqueue(std::make_unique<int>(42));
|
||||
|
||||
@@ -386,20 +386,17 @@ TEST_F(TestService, server_qos_depth) {
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(server_node);
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while ((server_cb_count_ < server_qos_profile.depth()) &&
|
||||
(std::chrono::steady_clock::now() - start) < 1s)
|
||||
{
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(server_node);
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
|
||||
// Spin an extra time to check if server QoS depth has been ignored,
|
||||
// so more server responses might be processed than expected.
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(server_node);
|
||||
|
||||
EXPECT_EQ(server_cb_count_, server_qos_profile.depth());
|
||||
}
|
||||
|
||||
@@ -87,9 +87,6 @@ protected:
|
||||
|
||||
TEST_F(TestServiceIntrospection, service_introspection_nominal)
|
||||
{
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
|
||||
auto request = std::make_shared<BasicTypes::Request>();
|
||||
request->set__bool_value(true);
|
||||
request->set__int64_value(42);
|
||||
@@ -109,7 +106,7 @@ TEST_F(TestServiceIntrospection, service_introspection_nominal)
|
||||
auto future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future, timeout));
|
||||
rclcpp::spin_until_future_complete(node, future, timeout));
|
||||
|
||||
BasicTypes::Response::SharedPtr response = future.get();
|
||||
ASSERT_EQ(response->bool_value, false);
|
||||
@@ -118,7 +115,7 @@ TEST_F(TestServiceIntrospection, service_introspection_nominal)
|
||||
// wrap up work to get all the service_event messages
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
std::map<uint8_t, std::shared_ptr<const BasicTypes::Event>> event_map;
|
||||
@@ -177,9 +174,6 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_OFF);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
|
||||
ASSERT_EQ(sub->get_publisher_count(), 0);
|
||||
|
||||
auto request = std::make_shared<BasicTypes::Request>();
|
||||
@@ -188,10 +182,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
auto future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future, timeout));
|
||||
rclcpp::spin_until_future_complete(node, future, timeout));
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while ((std::chrono::steady_clock::now() - start) < timeout) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
EXPECT_EQ(events.size(), 0U);
|
||||
|
||||
@@ -212,10 +206,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future, timeout));
|
||||
rclcpp::spin_until_future_complete(node, future, timeout));
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (events.size() < 2 && (std::chrono::steady_clock::now() - start) < timeout) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
EXPECT_EQ(events.size(), 2U);
|
||||
|
||||
@@ -236,10 +230,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future, timeout));
|
||||
rclcpp::spin_until_future_complete(node, future, timeout));
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (events.size() < 2 && (std::chrono::steady_clock::now() - start) < timeout) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
EXPECT_EQ(events.size(), 2U);
|
||||
|
||||
@@ -260,10 +254,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future, timeout));
|
||||
rclcpp::spin_until_future_complete(node, future, timeout));
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
EXPECT_EQ(events.size(), 4U);
|
||||
}
|
||||
@@ -275,9 +269,6 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
|
||||
service->configure_introspection(
|
||||
node->get_clock(), rclcpp::ServicesQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
|
||||
// Wait for the introspection to attach to our subscription
|
||||
size_t tries = 1000;
|
||||
while (this->sub->get_publisher_count() < 2 && tries-- > 0) {
|
||||
@@ -291,10 +282,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
|
||||
auto future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future, timeout));
|
||||
rclcpp::spin_until_future_complete(node, future, timeout));
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
EXPECT_EQ(events.size(), 4U);
|
||||
for (const auto & event : events) {
|
||||
@@ -319,10 +310,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future, timeout));
|
||||
rclcpp::spin_until_future_complete(node, future, timeout));
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
EXPECT_EQ(events.size(), 4U);
|
||||
for (const auto & event : events) {
|
||||
@@ -359,10 +350,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future, timeout));
|
||||
rclcpp::spin_until_future_complete(node, future, timeout));
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
EXPECT_EQ(events.size(), 4U);
|
||||
for (const auto & event : events) {
|
||||
@@ -399,10 +390,10 @@ TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_cont
|
||||
future = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future, timeout));
|
||||
rclcpp::spin_until_future_complete(node, future, timeout));
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (events.size() < 4 && (std::chrono::steady_clock::now() - start) < timeout) {
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
EXPECT_EQ(events.size(), 4U);
|
||||
for (const auto & event : events) {
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -25,7 +24,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/executors/single_threaded_executor.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "../mocking_utils/patch.hpp"
|
||||
@@ -670,212 +668,3 @@ TEST_P(TestSubscriptionInvalidIntraprocessQos, test_subscription_throws_intrapro
|
||||
options);},
|
||||
std::runtime_error("Unrecognized IntraProcessSetting value"));
|
||||
}
|
||||
|
||||
/*
|
||||
Testing disable and enable callbacks on subscriptions
|
||||
*/
|
||||
TEST_F(TestSubscription, disable_enable_callbacks)
|
||||
{
|
||||
const std::string topic_name = "~/test_disable";
|
||||
initialize();
|
||||
std::atomic<int> callback_count{0};
|
||||
|
||||
auto callback = [&callback_count](test_msgs::msg::Empty::ConstSharedPtr) {
|
||||
++callback_count;
|
||||
};
|
||||
|
||||
rclcpp::SubscriptionOptions sub_options;
|
||||
sub_options.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>(
|
||||
topic_name, 10U, callback, sub_options);
|
||||
|
||||
rclcpp::PublisherOptions pub_options;
|
||||
pub_options.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
|
||||
auto pub = node_->create_publisher<test_msgs::msg::Empty>(topic_name, 10U, pub_options);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node_);
|
||||
|
||||
// Wait for discovery
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while ((pub->get_subscription_count() == 0U || sub->get_publisher_count() == 0U) &&
|
||||
std::chrono::steady_clock::now() - start < 10s)
|
||||
{
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
|
||||
// Publish and verify callback is called
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
}
|
||||
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (callback_count.load() == 0 && std::chrono::steady_clock::now() - start < 30s) {
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Disable callbacks
|
||||
sub->disable_callbacks();
|
||||
|
||||
// Publish again and verify callback is NOT called
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
}
|
||||
|
||||
start = std::chrono::steady_clock::now();
|
||||
auto initial_count = callback_count.load();
|
||||
while (std::chrono::steady_clock::now() - start < 500ms) {
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
EXPECT_EQ(initial_count, callback_count.load()); // Should not increase
|
||||
|
||||
// Enable callbacks
|
||||
sub->enable_callbacks();
|
||||
|
||||
// Publish again and verify callback IS called
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
}
|
||||
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (callback_count.load() == initial_count && std::chrono::steady_clock::now() - start < 30s) {
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
EXPECT_EQ(callback_count.load(), initial_count + 1);
|
||||
}
|
||||
|
||||
TEST_F(TestSubscription, disable_enable_callbacks_intra_process)
|
||||
{
|
||||
const std::string topic_name = "~/test_disable_ipc";
|
||||
initialize(rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
std::atomic<int> callback_count{0};
|
||||
|
||||
auto callback = [&callback_count](test_msgs::msg::Empty::ConstSharedPtr) {
|
||||
++callback_count;
|
||||
};
|
||||
|
||||
auto sub = node_->create_subscription<test_msgs::msg::Empty>(topic_name, 10U, callback);
|
||||
auto pub = node_->create_publisher<test_msgs::msg::Empty>(topic_name, 10U);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node_);
|
||||
|
||||
// Publish and verify callback is called
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
}
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
while (callback_count.load() == 0 && std::chrono::steady_clock::now() - start < 30s) {
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
EXPECT_EQ(1, callback_count.load());
|
||||
|
||||
// Disable callbacks
|
||||
sub->disable_callbacks();
|
||||
|
||||
// Publish again and verify callback is NOT called
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
}
|
||||
|
||||
start = std::chrono::steady_clock::now();
|
||||
auto initial_count = callback_count.load();
|
||||
while (std::chrono::steady_clock::now() - start < 500ms) {
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
EXPECT_EQ(initial_count, callback_count.load());
|
||||
|
||||
// Enable callbacks
|
||||
sub->enable_callbacks();
|
||||
|
||||
// Publish again and verify callback IS called
|
||||
{
|
||||
test_msgs::msg::Empty msg;
|
||||
pub->publish(msg);
|
||||
}
|
||||
|
||||
start = std::chrono::steady_clock::now();
|
||||
while (callback_count.load() == initial_count && std::chrono::steady_clock::now() - start < 30s) {
|
||||
executor.spin_some();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
EXPECT_EQ(callback_count.load(), initial_count + 1);
|
||||
}
|
||||
|
||||
TEST_F(TestSubscription, disable_enable_event_callbacks)
|
||||
{
|
||||
initialize();
|
||||
std::atomic<int> deadline_callback_count{0};
|
||||
std::atomic<int> liveliness_callback_count{0};
|
||||
|
||||
rclcpp::SubscriptionOptions subscription_options;
|
||||
subscription_options.event_callbacks.deadline_callback =
|
||||
[&deadline_callback_count](rclcpp::QOSDeadlineRequestedInfo &) {
|
||||
++deadline_callback_count;
|
||||
};
|
||||
|
||||
subscription_options.event_callbacks.liveliness_callback =
|
||||
[&liveliness_callback_count](rclcpp::QOSLivelinessChangedInfo &) {
|
||||
++liveliness_callback_count;
|
||||
};
|
||||
|
||||
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {};
|
||||
|
||||
const auto qos = rclcpp::QoS(10U).deadline(100ms);
|
||||
|
||||
auto subscription = node_->create_subscription<test_msgs::msg::Empty>(
|
||||
"test_event_callbacks_topic", qos, do_nothing, subscription_options);
|
||||
|
||||
const auto & event_handlers = subscription->get_event_handlers();
|
||||
|
||||
// Initially, both callbacks counters should be zero
|
||||
EXPECT_EQ(deadline_callback_count, 0);
|
||||
EXPECT_EQ(liveliness_callback_count, 0);
|
||||
|
||||
// Execute events and disable all event handlers
|
||||
for (const auto & [event_type, handler] : event_handlers) {
|
||||
if (handler) {
|
||||
const std::shared_ptr<void> data = handler->take_data();
|
||||
handler->execute(data);
|
||||
EXPECT_NO_THROW(handler->disable());
|
||||
}
|
||||
}
|
||||
// Expect both callbacks to have been called once since they should be enabled by default
|
||||
EXPECT_EQ(deadline_callback_count, 1);
|
||||
EXPECT_EQ(liveliness_callback_count, 1);
|
||||
|
||||
// Execute events one more time and enable all event handlers
|
||||
for (const auto & [event_type, handler] : event_handlers) {
|
||||
if (handler) {
|
||||
const std::shared_ptr<void> data = handler->take_data();
|
||||
handler->execute(data);
|
||||
EXPECT_NO_THROW(handler->enable());
|
||||
}
|
||||
}
|
||||
// Expect no change since they were disabled
|
||||
EXPECT_EQ(deadline_callback_count, 1);
|
||||
EXPECT_EQ(liveliness_callback_count, 1);
|
||||
|
||||
// Execute events one more time
|
||||
for (const auto & [event_type, handler] : event_handlers) {
|
||||
if (handler) {
|
||||
const std::shared_ptr<void> data = handler->take_data();
|
||||
handler->execute(data);
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(deadline_callback_count, 2);
|
||||
EXPECT_EQ(liveliness_callback_count, 2);
|
||||
}
|
||||
|
||||
@@ -69,13 +69,11 @@ public:
|
||||
{
|
||||
using clock = std::chrono::system_clock;
|
||||
auto start = clock::now();
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
while (!condition()) {
|
||||
if ((clock::now() - start) > timeout) {
|
||||
return false;
|
||||
}
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -212,7 +212,7 @@ TEST_F(
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg) -> void {
|
||||
std::shared_ptr<std::string> msg) -> void {
|
||||
is_received = true;
|
||||
EXPECT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
@@ -230,7 +230,7 @@ TEST_F(
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg,
|
||||
std::shared_ptr<std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
EXPECT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
@@ -422,7 +422,7 @@ TEST_F(
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg) -> void {
|
||||
std::shared_ptr<std::string> msg) -> void {
|
||||
is_received = true;
|
||||
EXPECT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
@@ -440,7 +440,7 @@ TEST_F(
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg,
|
||||
std::shared_ptr<std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
EXPECT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
@@ -637,7 +637,7 @@ TEST_F(
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const double> msg) -> void {
|
||||
std::shared_ptr<double> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_EQ(message_data, *msg);
|
||||
};
|
||||
@@ -656,7 +656,7 @@ TEST_F(
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const double> msg,
|
||||
std::shared_ptr<double> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_EQ(message_data, *msg);
|
||||
@@ -862,7 +862,7 @@ TEST_F(
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const double> msg) -> void {
|
||||
std::shared_ptr<double> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_EQ(message_data, *msg);
|
||||
};
|
||||
@@ -882,7 +882,7 @@ TEST_F(
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const double> msg,
|
||||
std::shared_ptr<double> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_EQ(message_data, *msg);
|
||||
|
||||
@@ -158,15 +158,3 @@ TEST(TypesupportHelpersTest, test_throw_exception_with_invalid_type) {
|
||||
rclcpp::get_action_typesupport_handle(invalid_type, "rosidl_typesupport_cpp", *library),
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
TEST(TypesupportHelpersTest, throws_exception_if_filetype_has_multiple_slashes_at_start) {
|
||||
EXPECT_ANY_THROW(rclcpp::extract_type_identifier("//name_with_slashes_at_start"));
|
||||
}
|
||||
|
||||
TEST(TypesupportHelpersTestV3, ProcessesValidTypeWithWhitespace) {
|
||||
std::string package, middle, name;
|
||||
std::tie(package, middle, name) = rclcpp::extract_type_identifier(" package/ name ");
|
||||
EXPECT_EQ(package, "package");
|
||||
EXPECT_TRUE(middle.empty());
|
||||
EXPECT_EQ(name, "name");
|
||||
}
|
||||
|
||||
@@ -3,47 +3,37 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
30.1.5 (2026-02-09)
|
||||
29.5.7 (2026-02-09)
|
||||
-------------------
|
||||
* remove default: so that compiler can detect the missing case. (`#3048 <https://github.com/ros2/rclcpp/issues/3048>`_)
|
||||
* Update exception documentation for goal cancellation in ServerGoalHandle (`#3019 <https://github.com/ros2/rclcpp/issues/3019>`_)
|
||||
* Contributors: Andrei Costinescu, Tomoya Fujita
|
||||
* Update exception documentation for goal cancellation in ServerGoalHandle (`#3019 <https://github.com/ros2/rclcpp/issues/3019>`_) (`#3022 <https://github.com/ros2/rclcpp/issues/3022>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
30.1.4 (2025-12-23)
|
||||
29.5.6 (2025-12-23)
|
||||
-------------------
|
||||
|
||||
30.1.3 (2025-11-18)
|
||||
29.5.5 (2025-11-18)
|
||||
-------------------
|
||||
* Fix REP url locations (`#2987 <https://github.com/ros2/rclcpp/issues/2987>`_)
|
||||
* Contributors: Tim Clephas
|
||||
* Fix REP url locations (`#2987 <https://github.com/ros2/rclcpp/issues/2987>`_) (`#2989 <https://github.com/ros2/rclcpp/issues/2989>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
30.1.2 (2025-10-21)
|
||||
29.5.4 (2025-10-21)
|
||||
-------------------
|
||||
* it misses the iterator second to lock the weakptr. (`#2958 <https://github.com/ros2/rclcpp/issues/2958>`_)
|
||||
* try aborting before canceling 1st on dtor of ServerGoalHandle. (`#2953 <https://github.com/ros2/rclcpp/issues/2953>`_)
|
||||
* Contributors: Tomoya Fujita
|
||||
* it misses the iterator second to lock the weakptr. (`#2958 <https://github.com/ros2/rclcpp/issues/2958>`_) (`#2959 <https://github.com/ros2/rclcpp/issues/2959>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
30.1.1 (2025-09-11)
|
||||
29.5.3 (2025-09-11)
|
||||
-------------------
|
||||
* deprecate rclcpp::spin_some and rclcpp::spin_all (`#2848 <https://github.com/ros2/rclcpp/issues/2848>`_)
|
||||
* Contributors: Alberto Soragna
|
||||
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_) (`#2915 <https://github.com/ros2/rclcpp/issues/2915>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
30.1.0 (2025-07-29)
|
||||
-------------------
|
||||
* fix cmake deprecation (`#2914 <https://github.com/ros2/rclcpp/issues/2914>`_)
|
||||
* Contributors: mosfet80
|
||||
|
||||
30.0.0 (2025-07-01)
|
||||
29.5.2 (2025-07-07)
|
||||
-------------------
|
||||
|
||||
29.6.1 (2025-06-23)
|
||||
-------------------
|
||||
* Replace std::default_random_engine with std::mt19937 (rolling) (`#2843 <https://github.com/ros2/rclcpp/issues/2843>`_)
|
||||
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_)
|
||||
* Contributors: Alejandro Hernández Cordero, keeponoiro
|
||||
|
||||
29.6.0 (2025-04-25)
|
||||
29.5.1 (2025-06-23)
|
||||
-------------------
|
||||
* Replace std::default_random_engine with std::mt19937 (rolling) (`#2843 <https://github.com/ros2/rclcpp/issues/2843>`_) (`#2866 <https://github.com/ros2/rclcpp/issues/2866>`_)
|
||||
* Added missing chrono includes (`#2854 <https://github.com/ros2/rclcpp/issues/2854>`_) (`#2855 <https://github.com/ros2/rclcpp/issues/2855>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
29.5.0 (2025-04-18)
|
||||
-------------------
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
#include "action_msgs/msg/goal_status.hpp"
|
||||
|
||||
#include "rclcpp/logging.hpp"
|
||||
|
||||
#include "rclcpp_action/visibility_control.hpp"
|
||||
#include "rclcpp_action/types.hpp"
|
||||
|
||||
@@ -105,19 +103,11 @@ protected:
|
||||
_execute();
|
||||
|
||||
/// Transition the goal to canceled state if it never reached a terminal state.
|
||||
/// Returns true if transitioned to canceled, else false.
|
||||
/// \internal
|
||||
RCLCPP_ACTION_PUBLIC
|
||||
bool
|
||||
try_canceling() noexcept;
|
||||
|
||||
/// Transition the goal to aborted state if it never reached a terminal state.
|
||||
/// Returns true if transitioned to aborted, else false.
|
||||
/// \internal
|
||||
RCLCPP_ACTION_PUBLIC
|
||||
bool
|
||||
try_aborting() noexcept;
|
||||
|
||||
// End API for communication between ServerGoalHandleBase and ServerGoalHandle<>
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
@@ -253,22 +243,11 @@ public:
|
||||
|
||||
virtual ~ServerGoalHandle()
|
||||
{
|
||||
try {
|
||||
// Abort goal if handle was allowed to destruct without reaching a terminal state
|
||||
if (try_aborting()) {
|
||||
auto null_result = std::make_shared<typename ActionT::Impl::GetResultService::Response>();
|
||||
null_result->status = action_msgs::msg::GoalStatus::STATUS_ABORTED;
|
||||
on_terminal_state_(uuid_, null_result);
|
||||
} else if (try_canceling()) {
|
||||
// Cancel goal if handle was allowed to destruct without reaching a terminal state
|
||||
auto null_result = std::make_shared<typename ActionT::Impl::GetResultService::Response>();
|
||||
null_result->status = action_msgs::msg::GoalStatus::STATUS_CANCELED;
|
||||
on_terminal_state_(uuid_, null_result);
|
||||
}
|
||||
} catch (const std::exception & ex) {
|
||||
RCLCPP_DEBUG(
|
||||
rclcpp::get_logger("rclcpp_action"),
|
||||
"Failed to abort/cancel goal handler in destructor: %s", ex.what());
|
||||
// Cancel goal if handle was allowed to destruct without reaching a terminal state
|
||||
if (try_canceling()) {
|
||||
auto null_result = std::make_shared<typename ActionT::Impl::GetResultService::Response>();
|
||||
null_result->status = action_msgs::msg::GoalStatus::STATUS_CANCELED;
|
||||
on_terminal_state_(uuid_, null_result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_action</name>
|
||||
<version>30.1.5</version>
|
||||
<version>29.5.7</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -614,6 +614,10 @@ ClientBase::set_on_ready_callback(
|
||||
user_data);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw std::runtime_error("ClientBase::set_on_ready_callback: Unknown entity type.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
|
||||
@@ -908,10 +908,9 @@ ServerBase::set_on_ready_callback(
|
||||
break;
|
||||
}
|
||||
|
||||
case EntityType::Expired:
|
||||
{
|
||||
throw std::runtime_error("Expired entity type does not support callbacks");
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("ServerBase::set_on_ready_callback: Unknown entity type.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "rcl_action/action_server.h"
|
||||
#include "rcl_action/goal_handle.h"
|
||||
@@ -136,24 +135,6 @@ ServerGoalHandleBase::try_canceling() noexcept
|
||||
return RCL_RET_OK == ret;
|
||||
}
|
||||
|
||||
return is_cancelable;
|
||||
}
|
||||
|
||||
bool
|
||||
ServerGoalHandleBase::try_aborting() noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(rcl_handle_mutex_);
|
||||
rcl_ret_t ret;
|
||||
// Check if the goal is abortable
|
||||
const bool is_abortable = rcl_action_goal_handle_is_abortable(rcl_handle_.get());
|
||||
if (is_abortable) {
|
||||
// Transition to ABORTED
|
||||
ret = rcl_action_update_goal_state(rcl_handle_.get(), GOAL_EVENT_ABORT);
|
||||
if (RCL_RET_OK != ret) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return is_abortable;
|
||||
return false;
|
||||
}
|
||||
} // namespace rclcpp_action
|
||||
|
||||
@@ -518,11 +518,9 @@ TEST_F(TestServer, publish_status_accepted)
|
||||
|
||||
// 10 seconds
|
||||
const size_t max_tries = 10 * 1000 / 100;
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
for (size_t retry = 0; retry < max_tries && received_msgs.size() != 1u; ++retry) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
ASSERT_LT(0u, received_msgs.size());
|
||||
@@ -584,11 +582,9 @@ TEST_F(TestServer, publish_status_canceling)
|
||||
|
||||
// 10 seconds
|
||||
const size_t max_tries = 10 * 1000 / 100;
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 2u; ++retry) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
ASSERT_LT(0u, received_msgs.size());
|
||||
@@ -644,12 +640,10 @@ TEST_F(TestServer, publish_status_canceled)
|
||||
received_handle->canceled(std::make_shared<Fibonacci::Result>());
|
||||
|
||||
// 10 seconds
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
const size_t max_tries = 10 * 1000 / 100;
|
||||
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 3u; ++retry) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
ASSERT_LT(0u, received_msgs.size());
|
||||
@@ -703,12 +697,10 @@ TEST_F(TestServer, publish_status_succeeded)
|
||||
received_handle->succeed(std::make_shared<Fibonacci::Result>());
|
||||
|
||||
// 10 seconds
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
const size_t max_tries = 10 * 1000 / 100;
|
||||
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 2u; ++retry) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
ASSERT_LT(0u, received_msgs.size());
|
||||
@@ -762,12 +754,10 @@ TEST_F(TestServer, publish_status_aborted)
|
||||
received_handle->abort(std::make_shared<Fibonacci::Result>());
|
||||
|
||||
// 10 seconds
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
const size_t max_tries = 10 * 1000 / 100;
|
||||
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 2u; ++retry) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
ASSERT_LT(0u, received_msgs.size());
|
||||
@@ -824,12 +814,10 @@ TEST_F(TestServer, publish_feedback)
|
||||
received_handle->publish_feedback(sent_message);
|
||||
|
||||
// 10 seconds
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
const size_t max_tries = 10 * 1000 / 100;
|
||||
for (size_t retry = 0; retry < max_tries && received_msgs.size() < 1u; ++retry) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
}
|
||||
|
||||
ASSERT_EQ(1u, received_msgs.size());
|
||||
@@ -890,13 +878,10 @@ TEST_F(TestServer, get_result)
|
||||
result->sequence = {5, 8, 13, 21};
|
||||
received_handle->succeed(result);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
|
||||
// Wait for the result request to be received
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future));
|
||||
rclcpp::spin_until_future_complete(node, future));
|
||||
|
||||
auto response = future.get();
|
||||
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_SUCCEEDED, response->status);
|
||||
@@ -906,13 +891,13 @@ TEST_F(TestServer, get_result)
|
||||
rclcpp::sleep_for(2 * result_timeout);
|
||||
|
||||
// Allow for expiration to take place
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
|
||||
// Send and wait for another result request
|
||||
future = result_client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future));
|
||||
rclcpp::spin_until_future_complete(node, future));
|
||||
|
||||
response = future.get();
|
||||
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_UNKNOWN, response->status);
|
||||
@@ -961,12 +946,9 @@ TEST_F(TestServer, get_result_deferred)
|
||||
request->goal_id.uuid = uuid;
|
||||
auto future = result_client->async_send_request(request);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
|
||||
// Process request first
|
||||
rclcpp::sleep_for(std::chrono::milliseconds(10)); // Give a chance for the request to be served
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node);
|
||||
|
||||
// Send a result
|
||||
auto result = std::make_shared<Fibonacci::Result>();
|
||||
@@ -976,7 +958,7 @@ TEST_F(TestServer, get_result_deferred)
|
||||
// Wait for the result request to be received
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future));
|
||||
rclcpp::spin_until_future_complete(node, future));
|
||||
|
||||
auto response = future.get();
|
||||
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_SUCCEEDED, response->status);
|
||||
@@ -1060,13 +1042,10 @@ public:
|
||||
result->sequence = {5, 8, 13, 21};
|
||||
goal_handle_->succeed(result);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node_);
|
||||
|
||||
// Wait for the result request to be received
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future));
|
||||
rclcpp::spin_until_future_complete(node_, future));
|
||||
|
||||
auto response = future.get();
|
||||
EXPECT_EQ(action_msgs::msg::GoalStatus::STATUS_SUCCEEDED, response->status);
|
||||
@@ -1076,13 +1055,13 @@ public:
|
||||
rclcpp::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
// Allow for expiration to take place
|
||||
executor.spin_some();
|
||||
rclcpp::spin_some(node_);
|
||||
|
||||
// Send and wait for another result request
|
||||
future = result_client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::FutureReturnCode::SUCCESS,
|
||||
executor.spin_until_future_complete(future));
|
||||
rclcpp::spin_until_future_complete(node_, future));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
@@ -44,8 +44,6 @@ public:
|
||||
|
||||
bool try_cancel() {return try_canceling();}
|
||||
|
||||
bool try_abort() {return try_aborting();}
|
||||
|
||||
void cancel_goal() {_cancel_goal();}
|
||||
};
|
||||
|
||||
@@ -134,20 +132,6 @@ TEST_F(TestServerGoalHandle, abort) {
|
||||
EXPECT_THROW(handle_->abort(result), rclcpp::exceptions::RCLError);
|
||||
}
|
||||
|
||||
TEST_F(TestServerGoalHandle, try_abort) {
|
||||
handle_->execute();
|
||||
test_msgs::action::Fibonacci::Result::SharedPtr result =
|
||||
std::make_shared<test_msgs::action::Fibonacci::Result>();
|
||||
EXPECT_TRUE(handle_->try_abort());
|
||||
EXPECT_FALSE(handle_->is_canceling());
|
||||
EXPECT_FALSE(handle_->is_active());
|
||||
EXPECT_FALSE(handle_->is_executing());
|
||||
|
||||
auto mock = mocking_utils::patch_and_return(
|
||||
"lib:rclcpp_action", rcl_action_update_goal_state, RCL_RET_ERROR);
|
||||
EXPECT_THROW(handle_->abort(result), rclcpp::exceptions::RCLError);
|
||||
}
|
||||
|
||||
TEST_F(TestServerGoalHandle, succeed) {
|
||||
handle_->execute();
|
||||
test_msgs::action::Fibonacci::Result::SharedPtr result =
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user