From 0fb80463cc9d954571c976cba54072b08d75d7b5 Mon Sep 17 00:00:00 2001 From: Christophe Bedard Date: Thu, 4 Apr 2024 15:35:25 -0700 Subject: [PATCH] Add ConditionWaitReturnCode for spin_until_complete Signed-off-by: Christophe Bedard --- rclcpp/CMakeLists.txt | 2 +- .../rclcpp/condition_wait_return_code.hpp | 47 +++++++++++++++++++ rclcpp/include/rclcpp/executor.hpp | 13 ++--- rclcpp/include/rclcpp/executors.hpp | 10 ++-- rclcpp/include/rclcpp/future_return_code.hpp | 13 +---- ...ode.cpp => condition_wait_return_code.cpp} | 20 ++++---- rclcpp/test/rclcpp/CMakeLists.txt | 6 +++ .../test_condition_wait_return_code.cpp | 42 +++++++++++++++++ 8 files changed, 121 insertions(+), 32 deletions(-) create mode 100644 rclcpp/include/rclcpp/condition_wait_return_code.hpp rename rclcpp/src/rclcpp/{future_return_code.cpp => condition_wait_return_code.cpp} (65%) create mode 100644 rclcpp/test/rclcpp/test_condition_wait_return_code.cpp diff --git a/rclcpp/CMakeLists.txt b/rclcpp/CMakeLists.txt index c95df3e768..4e4706ef76 100644 --- a/rclcpp/CMakeLists.txt +++ b/rclcpp/CMakeLists.txt @@ -43,6 +43,7 @@ set(${PROJECT_NAME}_SRCS src/rclcpp/callback_group.cpp src/rclcpp/client.cpp src/rclcpp/clock.cpp + src/rclcpp/condition_wait_return_code.cpp src/rclcpp/context.cpp src/rclcpp/contexts/default_context.cpp src/rclcpp/create_generic_client.cpp @@ -73,7 +74,6 @@ set(${PROJECT_NAME}_SRCS src/rclcpp/expand_topic_or_service_name.cpp src/rclcpp/experimental/executors/events_executor/events_executor.cpp src/rclcpp/experimental/timers_manager.cpp - src/rclcpp/future_return_code.cpp src/rclcpp/generic_client.cpp src/rclcpp/generic_publisher.cpp src/rclcpp/generic_subscription.cpp diff --git a/rclcpp/include/rclcpp/condition_wait_return_code.hpp b/rclcpp/include/rclcpp/condition_wait_return_code.hpp new file mode 100644 index 0000000000..2aa863644d --- /dev/null +++ b/rclcpp/include/rclcpp/condition_wait_return_code.hpp @@ -0,0 +1,47 @@ +// Copyright 2014 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__CONDITION_WAIT_RETURN_CODE_HPP_ +#define RCLCPP__CONDITION_WAIT_RETURN_CODE_HPP_ + +#include +#include + +#include "rclcpp/visibility_control.hpp" + +namespace rclcpp +{ + +/// Return codes to be used with spin_until_complete. +/** + * SUCCESS: The condition wait is complete. This does not indicate that the operation succeeded. + * INTERRUPTED: The condition wait is not complete, spinning was interrupted by Ctrl-C or another + * error. + * TIMEOUT: Spinning timed out. + */ +enum class ConditionWaitReturnCode {SUCCESS, INTERRUPTED, TIMEOUT}; + +/// Stream operator for ConditionWaitReturnCode. +RCLCPP_PUBLIC +std::ostream & +operator<<(std::ostream & os, const ConditionWaitReturnCode & condition_wait_return_code); + +/// String conversion function for ConditionWaitReturnCode. +RCLCPP_PUBLIC +std::string +to_string(const ConditionWaitReturnCode & condition_wait_return_code); + +} // namespace rclcpp + +#endif // RCLCPP__CONDITION_WAIT_RETURN_CODE_HPP_ diff --git a/rclcpp/include/rclcpp/executor.hpp b/rclcpp/include/rclcpp/executor.hpp index b9bfb52c45..fc7df14371 100644 --- a/rclcpp/include/rclcpp/executor.hpp +++ b/rclcpp/include/rclcpp/executor.hpp @@ -32,6 +32,7 @@ #include "rclcpp/executors/executor_notify_waitable.hpp" #include "rcpputils/scope_exit.hpp" +#include "rclcpp/condition_wait_return_code.hpp" #include "rclcpp/context.hpp" #include "rclcpp/contexts/default_context.hpp" #include "rclcpp/guard_condition.hpp" @@ -361,7 +362,7 @@ class Executor * \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`. */ template - FutureReturnCode + ConditionWaitReturnCode spin_until_complete( const std::function & condition, std::chrono::duration timeout = std::chrono::duration(-1)) @@ -376,7 +377,7 @@ class Executor // Preliminary check, finish if condition is done already. if (condition()) { - return FutureReturnCode::SUCCESS; + return ConditionWaitReturnCode::SUCCESS; } if (spinning.exchange(true)) { @@ -388,7 +389,7 @@ class Executor spin_once_impl(timeout_left); if (condition()) { - return FutureReturnCode::SUCCESS; + return ConditionWaitReturnCode::SUCCESS; } // If the original timeout is < 0, then this is blocking, never TIMEOUT. if (timeout_ns < std::chrono::nanoseconds::zero()) { @@ -397,14 +398,14 @@ class Executor // Otherwise check if we still have time to wait, return TIMEOUT if not. auto now = std::chrono::steady_clock::now(); if (now >= end_time) { - return FutureReturnCode::TIMEOUT; + return ConditionWaitReturnCode::TIMEOUT; } // Subtract the elapsed time from the original timeout. timeout_left = std::chrono::duration_cast(end_time - now); } // The condition did not pass before ok() returned false, return INTERRUPTED. - return FutureReturnCode::INTERRUPTED; + return ConditionWaitReturnCode::INTERRUPTED; } /// Spin (blocking) for at least the given amount of duration. @@ -413,7 +414,7 @@ class Executor */ template void - spin_for(std::chrono::duration timeout duration) + spin_for(std::chrono::duration duration) { (void)spin_until_complete([]() {return false;}, duration); } diff --git a/rclcpp/include/rclcpp/executors.hpp b/rclcpp/include/rclcpp/executors.hpp index 92d6903856..c40ad7c884 100644 --- a/rclcpp/include/rclcpp/executors.hpp +++ b/rclcpp/include/rclcpp/executors.hpp @@ -18,10 +18,12 @@ #include #include +#include "rclcpp/condition_wait_return_code.hpp" #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/future_return_code.hpp" #include "rclcpp/node.hpp" #include "rclcpp/utilities.hpp" #include "rclcpp/visibility_control.hpp" @@ -79,7 +81,7 @@ using rclcpp::executors::SingleThreadedExecutor; * \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`. */ template -rclcpp::FutureReturnCode +rclcpp::ConditionWaitReturnCode spin_node_until_complete( rclcpp::Executor & executor, rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, @@ -95,7 +97,7 @@ spin_node_until_complete( } template -rclcpp::FutureReturnCode +rclcpp::ConditionWaitReturnCode spin_node_until_complete( rclcpp::Executor & executor, std::shared_ptr node_ptr, @@ -156,7 +158,7 @@ spin_node_until_future_complete( } // namespace executors template -rclcpp::FutureReturnCode +rclcpp::ConditionWaitReturnCode spin_until_complete( rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, const std::function & condition, @@ -167,7 +169,7 @@ spin_until_complete( } template -rclcpp::FutureReturnCode +rclcpp::ConditionWaitReturnCode spin_until_complete( std::shared_ptr node_ptr, const std::function & condition, diff --git a/rclcpp/include/rclcpp/future_return_code.hpp b/rclcpp/include/rclcpp/future_return_code.hpp index 0da67d7f7b..34fdcf7163 100644 --- a/rclcpp/include/rclcpp/future_return_code.hpp +++ b/rclcpp/include/rclcpp/future_return_code.hpp @@ -18,6 +18,7 @@ #include #include +#include "rclcpp/condition_wait_return_code.hpp" #include "rclcpp/visibility_control.hpp" namespace rclcpp @@ -30,17 +31,7 @@ namespace rclcpp * INTERRUPTED: The future is not complete, spinning was interrupted by Ctrl-C or another error. * TIMEOUT: Spinning timed out. */ -enum class FutureReturnCode {SUCCESS, INTERRUPTED, TIMEOUT}; - -/// Stream operator for FutureReturnCode. -RCLCPP_PUBLIC -std::ostream & -operator<<(std::ostream & os, const FutureReturnCode & future_return_code); - -/// String conversion function for FutureReturnCode. -RCLCPP_PUBLIC -std::string -to_string(const FutureReturnCode & future_return_code); +using FutureReturnCode = ConditionWaitReturnCode; } // namespace rclcpp diff --git a/rclcpp/src/rclcpp/future_return_code.cpp b/rclcpp/src/rclcpp/condition_wait_return_code.cpp similarity index 65% rename from rclcpp/src/rclcpp/future_return_code.cpp rename to rclcpp/src/rclcpp/condition_wait_return_code.cpp index 61e167dfb9..ff9b4f4920 100644 --- a/rclcpp/src/rclcpp/future_return_code.cpp +++ b/rclcpp/src/rclcpp/condition_wait_return_code.cpp @@ -16,31 +16,31 @@ #include #include -#include "rclcpp/future_return_code.hpp" +#include "rclcpp/condition_wait_return_code.hpp" namespace rclcpp { std::ostream & -operator<<(std::ostream & os, const rclcpp::FutureReturnCode & future_return_code) +operator<<(std::ostream & os, const rclcpp::ConditionWaitReturnCode & condition_wait_return_code) { - return os << to_string(future_return_code); + return os << to_string(condition_wait_return_code); } std::string -to_string(const rclcpp::FutureReturnCode & future_return_code) +to_string(const rclcpp::ConditionWaitReturnCode & condition_wait_return_code) { - using enum_type = std::underlying_type::type; + using enum_type = std::underlying_type::type; std::string prefix = "Unknown enum value ("; - std::string ret_as_string = std::to_string(static_cast(future_return_code)); - switch (future_return_code) { - case FutureReturnCode::SUCCESS: + std::string ret_as_string = std::to_string(static_cast(condition_wait_return_code)); + switch (condition_wait_return_code) { + case ConditionWaitReturnCode::SUCCESS: prefix = "SUCCESS ("; break; - case FutureReturnCode::INTERRUPTED: + case ConditionWaitReturnCode::INTERRUPTED: prefix = "INTERRUPTED ("; break; - case FutureReturnCode::TIMEOUT: + case ConditionWaitReturnCode::TIMEOUT: prefix = "TIMEOUT ("; break; } diff --git a/rclcpp/test/rclcpp/CMakeLists.txt b/rclcpp/test/rclcpp/CMakeLists.txt index c2e6b2bfe4..39ea50fec8 100644 --- a/rclcpp/test/rclcpp/CMakeLists.txt +++ b/rclcpp/test/rclcpp/CMakeLists.txt @@ -109,6 +109,12 @@ ament_add_gtest(test_function_traits test_function_traits.cpp) if(TARGET test_function_traits) target_link_libraries(test_function_traits ${PROJECT_NAME}) endif() +ament_add_gtest( + test_condition_wait_return_code + test_condition_wait_return_code.cpp) +if(TARGET test_condition_wait_return_code) + target_link_libraries(test_condition_wait_return_code ${PROJECT_NAME}) +endif() ament_add_gtest( test_future_return_code test_future_return_code.cpp) diff --git a/rclcpp/test/rclcpp/test_condition_wait_return_code.cpp b/rclcpp/test/rclcpp/test_condition_wait_return_code.cpp new file mode 100644 index 0000000000..3db4f09fcc --- /dev/null +++ b/rclcpp/test/rclcpp/test_condition_wait_return_code.cpp @@ -0,0 +1,42 @@ +// Copyright 2024 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 + +#include +#include + +#include "rclcpp/condition_wait_return_code.hpp" + +TEST(TestConditionWaitReturnCode, to_string) { + EXPECT_EQ( + "Unknown enum value (-1)", rclcpp::to_string(rclcpp::ConditionWaitReturnCode(-1))); + EXPECT_EQ( + "SUCCESS (0)", rclcpp::to_string(rclcpp::ConditionWaitReturnCode::SUCCESS)); + EXPECT_EQ( + "INTERRUPTED (1)", rclcpp::to_string(rclcpp::ConditionWaitReturnCode::INTERRUPTED)); + EXPECT_EQ( + "TIMEOUT (2)", rclcpp::to_string(rclcpp::ConditionWaitReturnCode::TIMEOUT)); + EXPECT_EQ( + "Unknown enum value (3)", rclcpp::to_string(rclcpp::ConditionWaitReturnCode(3))); + EXPECT_EQ( + "Unknown enum value (100)", rclcpp::to_string(rclcpp::ConditionWaitReturnCode(100))); +} + +TEST(TestConditionWaitReturnCode, ostream) { + std::ostringstream ostream; + + ostream << rclcpp::ConditionWaitReturnCode::SUCCESS; + ASSERT_EQ("SUCCESS (0)", ostream.str()); +}