Compare commits

...

54 Commits

Author SHA1 Message Date
methylDragon
32859cdf3c Remove RMW interfaces
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-07 18:16:43 -07:00
methylDragon
30210a2c02 Remove print methods
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-07 15:43:56 -07:00
methylDragon
d871af007a Use create instead of init
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-06 21:13:58 -07:00
methylDragon
29577dab24 Move dynamic type support struct to rosidl and fix mem issues
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-05 23:12:25 -07:00
methylDragon
000f788b65 Use dynamic typesupport identifier getter
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 21:12:02 -07:00
methylDragon
ca17caf6c4 Support type hashes
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
e7e9a298c0 Add initializers for description and source getters
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
8571b28664 Support type hashes
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
7e0d063154 Lint
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
113dc01dc7 Migrate methods to use return types
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
aac28e7b9f Remove dynamic data/type aliases
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
24e533eba7 Unalias dynamic typesupport types
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
ca1fe2b41b Implement SubscriptionType enum flag
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
57900a9f44 Add fixed string support
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
363861f70c Alias dynamic_data with dynamic_message, pass desc, and build ts top-down
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
9555859691 Use new deletes for memory management
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
78a568d14a Only use general type construction and implement default values
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
9ff28439d1 Implement direct taking of dynamic messages
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
bfcc29e64b Use dynamic message type support wrappers
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
927b9de2a5 Refactor dynamic typesupport to couple serialization support to objects
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
5af57f8010 Migrate to rosidl_dynamic_typesupport and update field IDs
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
0ce81c4fed Implement first cut
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
a2484be7c3 Take ownership of description, add print, and update ser support API
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
833efe0e2d Delete redundant wrapper class definitions
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
554ad022a6 Refine wrappers
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
a3e5d0a91a Implement dynamic message type support wrapper
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
methylDragon
b8fd304546 Implement dynamic typesupport wrappers
Signed-off-by: methylDragon <methylDragon@gmail.com>
2023-04-03 15:07:43 -07:00
Yadu
71a06985af Minor grammar fix (#2149)
Signed-off-by: Yadunund <yadunund@openrobotics.org>
2023-04-03 09:53:49 -07:00
Christopher Wecht
73d555b402 Fix unnecessary allocations in executor.cpp (#2135)
Signed-off-by: Christopher Wecht <cwecht@mailbox.org>
2023-04-03 09:01:39 -05:00
Tomoya Fujita
a5368e6fe4 add Logger::get_effective_level(). (#2141)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-03-29 21:50:17 -07:00
Emerson Knapp
20e9cd17f6 Remove deprecated header (#2139)
Signed-off-by: Emerson Knapp <emerson.b.knapp@gmail.com>
2023-03-26 08:45:36 -04:00
Barry Xu
cb08c79a0a Implement matched event (#2105)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2023-03-22 08:36:47 -05:00
Tomoya Fujita
bff59925de extract the result response before the callback is issued. (#2132)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-03-21 14:11:48 -07:00
Tomoya Fujita
1a796b5515 use allocator via init_options argument. (#2129)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-03-17 12:35:34 -07:00
Chris Lalancette
cbd48c0eb4 Fixes to silence some clang warnings. (#2127)
This does 2 separate things:

* Adds (void)unused_variable things where needed.
* Stops doing some checks on moved-from items in tests.

With this in place, most of the remaining clang static analysis
warnings are gone.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2023-03-14 15:38:20 -04:00
Michael Carroll
18dd05fba5 Documentation improvements on the executor (#2125)
Signed-off-by: Michael Carroll <mjcarroll@intrinsic.ai>
2023-03-13 17:23:43 -05:00
Barry Xu
232262c02a Avoid losing waitable handles while using MultiThreadedExecutor (#2109)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2023-03-13 10:10:24 -07:00
Chris Lalancette
6c4afb3a70 Hook up the incompatible type event inside of rclcpp (#2069)
* Rename QOSEventHandler* to EventHandler.

We are going to be using it for more than just QOS events, so
rename it to just EventHandler and EventHandlerBase for now.
Leave the old names in place but deprecated.

* Rename qos_event.hpp -> event_handler.hpp
* Revamp incompatible_qos callback setting.
* Add in incompatible type implementation.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2023-03-13 09:33:30 -04:00
Chris Lalancette
b6a803f48c Update all rclcpp packages to C++17. (#2121)
The main reason to do this is so that we can compile rclcpp
with the clang static analyzer.  As of clang++-14 (what is in
Ubuntu 22.04), the default still seems to be C++14, so we need
to specify C++17 so that new things in the rclcpp headers work
properly.

Further, due to reasons I don't fully understand, I needed to
set CMAKE_CXX_STANDARD_REQUIRED in order for clang to really use
that version.  So set this as well.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2023-03-07 14:43:58 -05:00
Chris Lalancette
dbe555a3c3 Use the correct macro for LifecycleNode::get_fully_qualified_name (#2117)
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-03-06 12:45:24 -05:00
mauropasse
1a9b117d53 Fix clang warning: bugprone-use-after-move (#2116)
Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2023-03-05 12:53:14 -05:00
Steve Macenski
11778f5048 add get_fully_qualified_name to rclcpp_lifecycle (#2115)
Signed-off-by: stevemacenski <stevenmacenski@gmail.com>
2023-03-04 16:13:56 -05:00
Nathan Wiebe Neufeldt
399f4df739 Fix the GoalUUID to_string representation (#1999)
* Fix expected results of the goal_uuid_to_string test

Signed-off-by: Nathan Wiebe Neufeldt <nwiebeneufeldt@clearpath.ai>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2023-03-02 07:45:22 -05:00
Chris Lalancette
e7890b7c62 19.3.0 2023-03-01 14:27:21 +00:00
Chris Lalancette
b589b490c3 Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-03-01 14:27:01 +00:00
Christophe Bedard
72c05ecee0 Fix memory leak in tracetools::get_symbol() (#2104)
Signed-off-by: Christophe Bedard <christophe.bedard@apex.ai>
2023-02-28 16:42:39 -06:00
Brian
968ce0a03f Service introspection (#1985)
* Implementation of service introspection.

To do this, we add a new method on the Client and
Service classes that allows the user to change the
introspection method at runtime.  These end up calling
into the rcl layer to do the actual configuration,
at which point service introspection messages will be
sent as configured.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Signed-off-by: Brian Chen <brian.chen@openrobotics.org>
2023-02-28 13:43:39 -05:00
Miguel Company
3062dec77e Allow publishing borrowed messages with intra-process enabled (#2108)
Signed-off-by: Miguel Company <MiguelCompany@eprosima.com>
2023-02-24 14:48:23 -08:00
Chen Lihui
9ea55ba620 to fix flaky test about TestTimeSource.callbacks (#2111)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-02-24 15:16:02 -05:00
Chris Lalancette
f57f4077fd 19.2.0 2023-02-24 18:27:42 +00:00
Chris Lalancette
006d1fa1df Changelog.
Signed-off-by: Chris Lalancette <clalancette@gmail.com>
2023-02-24 18:27:32 +00:00
Chen Lihui
b1e834a8df to create a sublogger while getting child of Logger (#1717)
* to create a sublogger while getting child of Logger

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2023-02-24 11:03:10 -05:00
Silvio Traversaro
28e4b1bd73 Fix documentation of Context class (#2107)
Signed-off-by: Silvio Traversaro <silvio@traversaro.it>
2023-02-16 16:32:10 -05:00
Alberto Soragna
35a5d6a66c fixes for rmw callbacks in qos_event class (#2102)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2023-02-16 07:56:47 -05:00
79 changed files with 6858 additions and 579 deletions

View File

@@ -2,6 +2,21 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19.3.0 (2023-03-01)
-------------------
* Fix memory leak in tracetools::get_symbol() (`#2104 <https://github.com/ros2/rclcpp/issues/2104>`_)
* Service introspection (`#1985 <https://github.com/ros2/rclcpp/issues/1985>`_)
* Allow publishing borrowed messages with intra-process enabled (`#2108 <https://github.com/ros2/rclcpp/issues/2108>`_)
* to fix flaky test about TestTimeSource.callbacks (`#2111 <https://github.com/ros2/rclcpp/issues/2111>`_)
* Contributors: Brian, Chen Lihui, Christophe Bedard, Miguel Company
19.2.0 (2023-02-24)
-------------------
* to create a sublogger while getting child of Logger (`#1717 <https://github.com/ros2/rclcpp/issues/1717>`_)
* Fix documentation of Context class (`#2107 <https://github.com/ros2/rclcpp/issues/2107>`_)
* fixes for rmw callbacks in qos_event class (`#2102 <https://github.com/ros2/rclcpp/issues/2102>`_)
* Contributors: Alberto Soragna, Chen Lihui, Silvio Traversaro
19.1.0 (2023-02-14)
-------------------
* Add support for timers on reset callback (`#1979 <https://github.com/ros2/rclcpp/issues/1979>`_)

View File

@@ -25,6 +25,7 @@ find_package(tracetools REQUIRED)
# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# About -Wno-sign-conversion: With Clang, -Wconversion implies -Wsign-conversion. There are a number of
@@ -48,6 +49,11 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/detail/rmw_implementation_specific_subscription_payload.cpp
src/rclcpp/detail/utilities.cpp
src/rclcpp/duration.cpp
src/rclcpp/dynamic_typesupport/dynamic_message.cpp
src/rclcpp/dynamic_typesupport/dynamic_message_type.cpp
src/rclcpp/dynamic_typesupport/dynamic_message_type_builder.cpp
src/rclcpp/dynamic_typesupport/dynamic_message_type_support.cpp
src/rclcpp/dynamic_typesupport/dynamic_serialization_support.cpp
src/rclcpp/event.cpp
src/rclcpp/exceptions/exceptions.cpp
src/rclcpp/executable_list.cpp
@@ -92,8 +98,9 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/parameter_value.cpp
src/rclcpp/publisher_base.cpp
src/rclcpp/qos.cpp
src/rclcpp/qos_event.cpp
src/rclcpp/event_handler.cpp
src/rclcpp/qos_overriding_options.cpp
src/rclcpp/dynamic_subscription.cpp
src/rclcpp/serialization.cpp
src/rclcpp/serialized_message.cpp
src/rclcpp/service.cpp

View File

@@ -191,10 +191,14 @@ public:
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && arg) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
tracetools::get_symbol(arg));
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(arg);
DO_TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
symbol);
std::free(symbol);
}
}, callback_);
#endif // TRACETOOLS_DISABLED
}

View File

@@ -965,10 +965,14 @@ public:
#ifndef TRACETOOLS_DISABLED
std::visit(
[this](auto && callback) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
tracetools::get_symbol(callback));
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(callback);
DO_TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
symbol);
std::free(symbol);
}
}, callback_variant_);
#endif // TRACETOOLS_DISABLED
}

View File

@@ -16,14 +16,15 @@
#define RCLCPP__CLIENT_HPP_
#include <atomic>
#include <functional>
#include <future>
#include <unordered_map>
#include <memory>
#include <mutex>
#include <optional> // NOLINT, cpplint doesn't think this is a cpp std header
#include <sstream>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <variant> // NOLINT
#include <vector>
@@ -31,8 +32,10 @@
#include "rcl/client.h"
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
#include "rcl/service_introspection.h"
#include "rcl/wait.h"
#include "rclcpp/clock.hpp"
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
@@ -467,15 +470,13 @@ public:
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
const std::string & service_name,
rcl_client_options_t & client_options)
: ClientBase(node_base, node_graph)
: ClientBase(node_base, node_graph),
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
{
using rosidl_typesupport_cpp::get_service_type_support_handle;
auto service_type_support_handle =
get_service_type_support_handle<ServiceT>();
rcl_ret_t ret = rcl_client_init(
this->get_client_handle().get(),
this->get_rcl_node_handle(),
service_type_support_handle,
srv_type_support_handle_,
service_name.c_str(),
&client_options);
if (ret != RCL_RET_OK) {
@@ -781,6 +782,33 @@ public:
return old_size - pending_requests_.size();
}
/// Configure client introspection.
/**
* \param[in] clock clock to use to generate introspection timestamps
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
* \param[in] introspection_state the state to set introspection to
*/
void
configure_introspection(
Clock::SharedPtr clock, const QoS & qos_service_event_pub,
rcl_service_introspection_state_t introspection_state)
{
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
rcl_ret_t ret = rcl_client_configure_service_introspection(
client_handle_.get(),
node_handle_.get(),
clock->get_clock_handle(),
srv_type_support_handle_,
pub_opts,
introspection_state);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure client introspection");
}
}
protected:
using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
using CallbackWithRequestTypeValueVariant = std::tuple<
@@ -831,6 +859,9 @@ protected:
CallbackInfoVariant>>
pending_requests_;
std::mutex pending_requests_mutex_;
private:
const rosidl_service_type_support_t * srv_type_support_handle_;
};
} // namespace rclcpp

View File

@@ -65,8 +65,11 @@ using PreShutdownCallbackHandle = ShutdownCallbackHandle;
/// Context which encapsulates shared state between nodes and other similar entities.
/**
* A context also represents the lifecycle between init and shutdown of rclcpp.
* It is often used in conjunction with rclcpp::init, or rclcpp::init_local,
* and rclcpp::shutdown.
* Nodes may be attached to a particular context by passing to the rclcpp::Node
* constructor a rclcpp::NodeOptions instance in which the Context is set via
* rclcpp::NodeOptions::context.
* Nodes will be automatically removed from the context when destructed.
* Contexts may be shutdown by calling rclcpp::shutdown.
*/
class Context : public std::enable_shared_from_this<Context>
{

View File

@@ -0,0 +1,176 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
#define RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
#include <rosidl_dynamic_typesupport/identifier.h>
#include <functional>
#include <memory>
#include <string>
#include "rcpputils/shared_library.hpp"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/typesupport_helpers.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// %Subscription for messages whose type descriptions are obtained at runtime.
/**
* Since the type is not known at compile time, this is not a template, and the dynamic library
* containing type support information has to be identified and loaded based on the type name.
*
* NOTE(methylDragon): No considerations for intra-process handling are made.
*/
class DynamicSubscription : public rclcpp::SubscriptionBase
{
public:
// cppcheck-suppress unknownMacro
RCLCPP_SMART_PTR_DEFINITIONS(DynamicSubscription)
template<typename AllocatorT = std::allocator<void>>
DynamicSubscription(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
rclcpp::dynamic_typesupport::DynamicMessageTypeSupport::SharedPtr type_support,
const std::string & topic_name,
const rclcpp::QoS & qos,
std::function<void(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr,
std::shared_ptr<const rosidl_runtime_c__type_description__TypeDescription>
)> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
bool use_take_dynamic_message = true)
: SubscriptionBase(
node_base,
*(type_support->get_rosidl_message_type_support()),
topic_name,
options.to_rcl_subscription_options(
qos),
options.event_callbacks,
options.use_default_callbacks,
use_take_dynamic_message ? SubscriptionType::DYNAMIC_MESSAGE_DIRECT : SubscriptionType::DYNAMIC_MESSAGE_FROM_SERIALIZED), // NOLINT
ts_(type_support),
callback_(callback),
serialization_support_(nullptr),
dynamic_message_(nullptr),
dynamic_message_type_(nullptr)
{
if (!type_support) {
throw std::runtime_error("DynamicMessageTypeSupport cannot be nullptr!");
}
if (type_support->get_rosidl_message_type_support()->typesupport_identifier !=
rosidl_get_dynamic_typesupport_identifier())
{
throw std::runtime_error(
"DynamicSubscription must use dynamic type introspection type support!");
}
serialization_support_ = type_support->get_shared_dynamic_serialization_support();
dynamic_message_type_ = type_support->get_shared_dynamic_message_type()->clone_shared();
dynamic_message_ = type_support->get_shared_dynamic_message()->clone_shared();
}
// TODO(methylDragon):
/// Deferred type description constructor, only usable if the middleware implementation supports
/// type discovery
RCLCPP_PUBLIC
virtual ~DynamicSubscription() = default;
// Same as create_serialized_message() as the subscription is to serialized_messages only
RCLCPP_PUBLIC
std::shared_ptr<void> create_message() override;
RCLCPP_PUBLIC
std::shared_ptr<rclcpp::SerializedMessage> create_serialized_message() override;
/// Cast the message to a rclcpp::SerializedMessage and call the callback.
RCLCPP_PUBLIC
void handle_message(
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) override;
/// Handle dispatching rclcpp::SerializedMessage to user callback.
RCLCPP_PUBLIC
void
handle_serialized_message(
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
const rclcpp::MessageInfo & message_info) override;
/// This function is currently not implemented.
RCLCPP_PUBLIC
void handle_loaned_message(
void * loaned_message, const rclcpp::MessageInfo & message_info) override;
// Same as return_serialized_message() as the subscription is to serialized_messages only
RCLCPP_PUBLIC
void return_message(std::shared_ptr<void> & message) override;
RCLCPP_PUBLIC
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
// DYNAMIC TYPE ==================================================================================
// TODO(methylDragon): Reorder later
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
get_shared_dynamic_message_type() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr get_shared_dynamic_message() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override;
RCLCPP_PUBLIC
void return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override;
RCLCPP_PUBLIC
void handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info) override;
private:
RCLCPP_DISABLE_COPY(DynamicSubscription)
rclcpp::dynamic_typesupport::DynamicMessageTypeSupport::SharedPtr ts_;
std::function<void(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr,
std::shared_ptr<const rosidl_runtime_c__type_description__TypeDescription>
)> callback_;
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr serialization_support_;
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr dynamic_message_;
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr dynamic_message_type_;
};
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_

View File

@@ -0,0 +1,327 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
#include <rosidl_dynamic_typesupport/types.h>
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
#include <cstdint>
#include <cstddef>
#include <memory>
#include <string>
#include "rclcpp/exceptions.hpp"
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#endif
#define __DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN(ValueT, FunctionT) \
template<> \
ValueT \
DynamicMessage::get_value<ValueT>(rosidl_dynamic_typesupport_member_id_t id) \
{ \
ValueT out; \
rosidl_dynamic_typesupport_dynamic_data_get_ ## FunctionT ## _value( \
rosidl_dynamic_data_.get(), id, &out); \
return out; \
}
#define __DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
template<> \
ValueT \
DynamicMessage::get_value<ValueT>(const std::string & name) \
{ \
return get_value<ValueT>(get_member_id(name)); \
}
#define __DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN(ValueT, FunctionT) \
template<> \
void \
DynamicMessage::set_value<ValueT>(rosidl_dynamic_typesupport_member_id_t id, ValueT value) \
{ \
rosidl_dynamic_typesupport_dynamic_data_set_ ## FunctionT ## _value( \
rosidl_dynamic_data_.get(), id, value); \
}
#define __DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
template<> \
void \
DynamicMessage::set_value<ValueT>(const std::string & name, ValueT value) \
{ \
set_value<ValueT>(get_member_id(name), value); \
}
#define __DYNAMIC_MESSAGE_INSERT_VALUE(ValueT, FunctionT) \
template<> \
rosidl_dynamic_typesupport_member_id_t \
DynamicMessage::insert_value<ValueT>(ValueT value) \
{ \
rosidl_dynamic_typesupport_member_id_t out; \
rosidl_dynamic_typesupport_dynamic_data_insert_ ## FunctionT ## _value( \
rosidl_dynamic_data_.get(), value, &out); \
return out; \
}
#define DYNAMIC_MESSAGE_DEFINITIONS(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
__DYNAMIC_MESSAGE_INSERT_VALUE(ValueT, FunctionT)
namespace rclcpp
{
namespace dynamic_typesupport
{
/**
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
*
* Explicitly:
* - Basic types: bool, byte, char
* - Float types: float, double
* - Int types: int8_t, int16_t, int32_t, int64_t
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
* - String types: std::string, std::u16string
*/
DYNAMIC_MESSAGE_DEFINITIONS(bool, bool);
// DYNAMIC_MESSAGE_DEFINITIONS(std::byte, byte);
DYNAMIC_MESSAGE_DEFINITIONS(char, char);
DYNAMIC_MESSAGE_DEFINITIONS(float, float32);
DYNAMIC_MESSAGE_DEFINITIONS(double, float64);
DYNAMIC_MESSAGE_DEFINITIONS(int8_t, int8);
DYNAMIC_MESSAGE_DEFINITIONS(int16_t, int16);
DYNAMIC_MESSAGE_DEFINITIONS(int32_t, int32);
DYNAMIC_MESSAGE_DEFINITIONS(int64_t, int64);
DYNAMIC_MESSAGE_DEFINITIONS(uint8_t, uint8);
DYNAMIC_MESSAGE_DEFINITIONS(uint16_t, uint16);
DYNAMIC_MESSAGE_DEFINITIONS(uint32_t, uint32);
DYNAMIC_MESSAGE_DEFINITIONS(uint64_t, uint64);
// DYNAMIC_MESSAGE_DEFINITIONS(std::string, std::string);
// DYNAMIC_MESSAGE_DEFINITIONS(std::u16string, std::u16string);
// Byte and String getters have a different implementation and are defined below
// BYTE ============================================================================================
template<>
std::byte
DynamicMessage::get_value<std::byte>(rosidl_dynamic_typesupport_member_id_t id)
{
unsigned char out;
rosidl_dynamic_typesupport_dynamic_data_get_byte_value(get_rosidl_dynamic_data(), id, &out);
return static_cast<std::byte>(out);
}
template<>
std::byte
DynamicMessage::get_value<std::byte>(const std::string & name)
{
return get_value<std::byte>(get_member_id(name));
}
template<>
void
DynamicMessage::set_value<std::byte>(
rosidl_dynamic_typesupport_member_id_t id, const std::byte value)
{
rosidl_dynamic_typesupport_dynamic_data_set_byte_value(
rosidl_dynamic_data_.get(), id, static_cast<unsigned char>(value));
}
template<>
void
DynamicMessage::set_value<std::byte>(const std::string & name, const std::byte value)
{
set_value<std::byte>(get_member_id(name), value);
}
template<>
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_value<std::byte>(const std::byte value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_byte_value(
rosidl_dynamic_data_.get(), static_cast<unsigned char>(value), &out);
return out;
}
// STRINGS =========================================================================================
template<>
std::string
DynamicMessage::get_value<std::string>(rosidl_dynamic_typesupport_member_id_t id)
{
size_t buf_length;
char * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_string_value(
get_rosidl_dynamic_data(), id, &buf, &buf_length);
auto out = std::string(buf, buf_length);
delete buf;
return out;
}
template<>
std::u16string
DynamicMessage::get_value<std::u16string>(rosidl_dynamic_typesupport_member_id_t id)
{
size_t buf_length;
char16_t * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_wstring_value(
get_rosidl_dynamic_data(), id, &buf, &buf_length);
auto out = std::u16string(buf, buf_length);
delete buf;
return out;
}
template<>
std::string
DynamicMessage::get_value<std::string>(const std::string & name)
{
return get_value<std::string>(get_member_id(name));
}
template<>
std::u16string
DynamicMessage::get_value<std::u16string>(const std::string & name)
{
return get_value<std::u16string>(get_member_id(name));
}
template<>
void
DynamicMessage::set_value<std::string>(
rosidl_dynamic_typesupport_member_id_t id, const std::string value)
{
rosidl_dynamic_typesupport_dynamic_data_set_string_value(
rosidl_dynamic_data_.get(), id, value.c_str(), value.size());
}
template<>
void
DynamicMessage::set_value<std::u16string>(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value)
{
rosidl_dynamic_typesupport_dynamic_data_set_wstring_value(
rosidl_dynamic_data_.get(), id, value.c_str(), value.size());
}
template<>
void
DynamicMessage::set_value<std::string>(const std::string & name, const std::string value)
{
set_value<std::string>(get_member_id(name), value);
}
template<>
void
DynamicMessage::set_value<std::u16string>(const std::string & name, const std::u16string value)
{
set_value<std::u16string>(get_member_id(name), value);
}
template<>
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_value<std::string>(const std::string value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_string_value(
rosidl_dynamic_data_.get(), value.c_str(), value.size(), &out);
return out;
}
template<>
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_value<std::u16string>(const std::u16string value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_wstring_value(
rosidl_dynamic_data_.get(), value.c_str(), value.size(), &out);
return out;
}
// THROW FOR UNSUPPORTED TYPES =====================================================================
template<typename ValueT>
ValueT
DynamicMessage::get_value(rosidl_dynamic_typesupport_member_id_t id)
{
throw rclcpp::exceptions::UnimplementedError("get_value is not implemented for input type");
}
template<typename ValueT>
ValueT
DynamicMessage::get_value(const std::string & name)
{
throw rclcpp::exceptions::UnimplementedError("get_value is not implemented for input type");
}
template<typename ValueT>
void
DynamicMessage::set_value(
rosidl_dynamic_typesupport_member_id_t id, ValueT value)
{
throw rclcpp::exceptions::UnimplementedError("set_value is not implemented for input type");
}
template<typename ValueT>
void
DynamicMessage::set_value(const std::string & name, ValueT value)
{
throw rclcpp::exceptions::UnimplementedError("set_value is not implemented for input type");
}
template<typename ValueT>
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_value(ValueT value)
{
throw rclcpp::exceptions::UnimplementedError("insert_value is not implemented for input type");
}
} // namespace dynamic_typesupport
} // namespace rclcpp
#undef __DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN
#undef __DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN
#undef __DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN
#undef __DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN
#undef __DYNAMIC_MESSAGE_INSERT_VALUE
#undef DYNAMIC_MESSAGE_DEFINITIONS
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_

View File

@@ -0,0 +1,189 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
#include <rosidl_dynamic_typesupport/types.h>
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
#include <cstdint>
#include <cstddef>
#include <memory>
#include <string>
#include "rclcpp/exceptions.hpp"
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
#endif
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN(MemberT, FunctionT) \
template<> \
void \
DynamicMessageTypeBuilder::add_member<MemberT>( \
rosidl_dynamic_typesupport_member_id_t id, \
const std::string & name, \
const std::string & default_value) \
{ \
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _member( \
rosidl_dynamic_type_builder_.get(), \
id, name.c_str(), name.size(), default_value.c_str(), default_value.size()); \
}
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN(MemberT, FunctionT) \
template<> \
void \
DynamicMessageTypeBuilder::add_array_member<MemberT>( \
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, \
size_t array_length, \
const std::string & default_value) \
{ \
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _array_member( \
rosidl_dynamic_type_builder_.get(), \
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(), \
array_length); \
}
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
template<> \
void \
DynamicMessageTypeBuilder::add_unbounded_sequence_member<MemberT>( \
rosidl_dynamic_typesupport_member_id_t id, \
const std::string & name, \
const std::string & default_value) \
{ \
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## \
_unbounded_sequence_member( \
rosidl_dynamic_type_builder_.get(), \
id, name.c_str(), name.size(), default_value.c_str(), default_value.size()); \
}
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
template<> \
void \
DynamicMessageTypeBuilder::add_bounded_sequence_member<MemberT>( \
rosidl_dynamic_typesupport_member_id_t id, \
const std::string & name, \
size_t sequence_bound, \
const std::string & default_value) \
{ \
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _bounded_sequence_member( \
rosidl_dynamic_type_builder_.get(), \
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(), \
sequence_bound); \
}
#define DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(MemberT, FunctionT) \
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN(MemberT, FunctionT) \
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN(MemberT, FunctionT) \
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
namespace rclcpp
{
namespace dynamic_typesupport
{
/**
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
*
* Explicitly:
* - Basic types: bool, byte, char
* - Float types: float, double
* - Int types: int8_t, int16_t, int32_t, int64_t
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
* - String types: std::string, std::u16string
*/
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(bool, bool);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::byte, byte);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(char, char);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(float, float32);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(double, float64);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int8_t, int8);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int16_t, int16);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int32_t, int32);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int64_t, int64);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint8_t, uint8);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint16_t, uint16);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint32_t, uint32);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint64_t, uint64);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::string, string);
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::u16string, wstring);
// THROW FOR UNSUPPORTED TYPES =====================================================================
template<typename MemberT>
void
DynamicMessageTypeBuilder::add_member(
rosidl_dynamic_typesupport_member_id_t id,
const std::string & name,
const std::string & default_value)
{
throw rclcpp::exceptions::UnimplementedError(
"add_member is not implemented for input type");
}
template<typename MemberT>
void
DynamicMessageTypeBuilder::add_array_member(
rosidl_dynamic_typesupport_member_id_t id,
const std::string & name,
size_t array_length, const std::string & default_value)
{
throw rclcpp::exceptions::UnimplementedError(
"add_array_member is not implemented for input type");
}
template<typename MemberT>
void
DynamicMessageTypeBuilder::add_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id,
const std::string & name,
const std::string & default_value)
{
throw rclcpp::exceptions::UnimplementedError(
"add_unbounded_sequence_member is not implemented for input type");
}
template<typename MemberT>
void
DynamicMessageTypeBuilder::add_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id,
const std::string & name,
size_t sequence_bound,
const std::string & default_value)
{
throw rclcpp::exceptions::UnimplementedError(
"add_bounded_sequence_member is not implemented for input type");
}
} // namespace dynamic_typesupport
} // namespace rclcpp
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN
#undef DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_

View File

@@ -0,0 +1,430 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
#include <rcl/types.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
class DynamicMessageType;
class DynamicMessageTypeBuilder;
/// Utility wrapper class for rosidl_dynamic_typesupport_dynamic_data_t *
/**
* This class:
* - Manages the lifetime of the raw pointer.
* - Exposes getter methods to get the raw pointer and shared pointers
* - Exposes the underlying serialization support API
*
* Ownership:
* - This class borrows the rosidl_dynamic_typesupport_serialization_support_t stored in the passed
* DynamicSerializationSupport. So it cannot outlive the DynamicSerializationSupport.
* - The DynamicSerializationSupport's rosidl_dynamic_typesupport_serialization_support_t pointer
* must point to the same location in memory as the stored raw pointer!
*
* Note: This class is meant to map to the lower level rosidl_dynamic_typesupport_dynamic_data_t,
* even though rosidl_dynamic_typesupport_dynamic_data_t is equivalent to
* rosidl_dynamic_typesupport_dynamic_data_t, exposing the fundamental methods available to
* rosidl_dynamic_typesupport_dynamic_data_t, allowing the user to access the data's fields.
*/
class DynamicMessage : public std::enable_shared_from_this<DynamicMessage>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessage)
// CONSTRUCTION ==================================================================================
// Most constructors require a passed in DynamicSerializationSupport::SharedPtr, to extend the
// lifetime of the serialization support (if the constructor cannot otherwise get it from args).
//
// In cases where a dynamic data pointer is passed, the serialization support composed by
// the data should be the exact same object managed by the DynamicSerializationSupport,
// otherwise the lifetime management will not work properly.
/// Construct a new DynamicMessage with the provided dynamic type builder
RCLCPP_PUBLIC
explicit DynamicMessage(std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder);
/// Construct a new DynamicMessage with the provided dynamic type
RCLCPP_PUBLIC
explicit DynamicMessage(std::shared_ptr<DynamicMessageType> dynamic_type);
/// Assume ownership of raw pointer
RCLCPP_PUBLIC
DynamicMessage(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data);
/// Copy shared pointer
RCLCPP_PUBLIC
DynamicMessage(
DynamicSerializationSupport::SharedPtr serialization_support,
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_data_t> rosidl_dynamic_data);
/// Loaning constructor
/// Must only be called with raw ptr obtained from loaning!
// NOTE(methylDragon): I'd put this in protected, but I need this exposed to
// enable_shared_from_this...
RCLCPP_PUBLIC
DynamicMessage(
DynamicMessage::SharedPtr parent_data,
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_loaned_data);
// NOTE(methylDragon): Deliberately no constructor from description to nudge users towards using
// construction from dynamic type/builder, which is more efficient
/// Copy constructor
RCLCPP_PUBLIC
DynamicMessage(const DynamicMessage & other);
/// Move constructor
RCLCPP_PUBLIC
DynamicMessage(DynamicMessage && other) noexcept;
/// Copy assignment
RCLCPP_PUBLIC
DynamicMessage & operator=(const DynamicMessage & other);
/// Move assignment
RCLCPP_PUBLIC
DynamicMessage & operator=(DynamicMessage && other) noexcept;
RCLCPP_PUBLIC
virtual ~DynamicMessage();
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_library_identifier() const;
RCLCPP_PUBLIC
const std::string
get_name() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_dynamic_data_t *
get_rosidl_dynamic_data();
RCLCPP_PUBLIC
const rosidl_dynamic_typesupport_dynamic_data_t *
get_rosidl_dynamic_data() const;
RCLCPP_PUBLIC
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_data_t>
get_shared_rosidl_dynamic_data();
RCLCPP_PUBLIC
std::shared_ptr<const rosidl_dynamic_typesupport_dynamic_data_t>
get_shared_rosidl_dynamic_data() const;
RCLCPP_PUBLIC
DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support();
RCLCPP_PUBLIC
DynamicSerializationSupport::ConstSharedPtr
get_shared_dynamic_serialization_support() const;
RCLCPP_PUBLIC
size_t
get_item_count() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
get_member_id(size_t index) const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
get_member_id(const std::string & name) const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
get_array_index(size_t index) const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
get_array_index(const std::string & name) const;
// METHODS =======================================================================================
RCLCPP_PUBLIC
DynamicMessage
clone() const;
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
clone_shared() const;
RCLCPP_PUBLIC
DynamicMessage
init_from_type(DynamicMessageType & type) const;
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
init_from_type_shared(DynamicMessageType & type) const;
RCLCPP_PUBLIC
bool
equals(const DynamicMessage & other) const;
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
loan_value(rosidl_dynamic_typesupport_member_id_t id);
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
loan_value(const std::string & name);
RCLCPP_PUBLIC
void
clear_all_values();
RCLCPP_PUBLIC
void
clear_nonkey_values();
RCLCPP_PUBLIC
void
clear_value(rosidl_dynamic_typesupport_member_id_t id);
RCLCPP_PUBLIC
void
clear_value(const std::string & name);
RCLCPP_PUBLIC
void
clear_sequence();
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_sequence_data();
RCLCPP_PUBLIC
void
remove_sequence_data(rosidl_dynamic_typesupport_member_id_t index);
RCLCPP_PUBLIC
bool
serialize(rcl_serialized_message_t * buffer);
RCLCPP_PUBLIC
bool
deserialize(rcl_serialized_message_t * buffer);
// MEMBER ACCESS TEMPLATES =======================================================================
/**
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
*
* Explicitly:
* - Basic types: bool, byte, char
* - Float types: float, double
* - Int types: int8_t, int16_t, int32_t, int64_t
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
* - String types: std::string, std::u16string
*/
template<typename ValueT>
ValueT
get_value(rosidl_dynamic_typesupport_member_id_t id);
template<typename ValueT>
ValueT
get_value(const std::string & name);
template<typename ValueT>
void
set_value(rosidl_dynamic_typesupport_member_id_t id, ValueT value);
template<typename ValueT>
void
set_value(const std::string & name, ValueT value);
template<typename ValueT>
rosidl_dynamic_typesupport_member_id_t
insert_value(ValueT value);
// FIXED STRING MEMBER ACCESS ====================================================================
RCLCPP_PUBLIC
const std::string
get_fixed_string_value(rosidl_dynamic_typesupport_member_id_t id, size_t string_length);
RCLCPP_PUBLIC
const std::string
get_fixed_string_value(const std::string & name, size_t string_length);
RCLCPP_PUBLIC
const std::u16string
get_fixed_wstring_value(rosidl_dynamic_typesupport_member_id_t id, size_t wstring_length);
RCLCPP_PUBLIC
const std::u16string
get_fixed_wstring_value(const std::string & name, size_t wstring_length);
RCLCPP_PUBLIC
void
set_fixed_string_value(
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_length);
RCLCPP_PUBLIC
void
set_fixed_string_value(const std::string & name, const std::string value, size_t string_length);
RCLCPP_PUBLIC
void
set_fixed_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_length);
RCLCPP_PUBLIC
void
set_fixed_wstring_value(
const std::string & name, const std::u16string value, size_t wstring_length);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_fixed_string_value(const std::string value, size_t string_length);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_fixed_wstring_value(const std::u16string value, size_t wstring_length);
// BOUNDED STRING MEMBER ACCESS ==================================================================
RCLCPP_PUBLIC
const std::string
get_bounded_string_value(rosidl_dynamic_typesupport_member_id_t id, size_t string_bound);
RCLCPP_PUBLIC
const std::string
get_bounded_string_value(const std::string & name, size_t string_bound);
RCLCPP_PUBLIC
const std::u16string
get_bounded_wstring_value(rosidl_dynamic_typesupport_member_id_t id, size_t wstring_bound);
RCLCPP_PUBLIC
const std::u16string
get_bounded_wstring_value(const std::string & name, size_t wstring_bound);
RCLCPP_PUBLIC
void
set_bounded_string_value(
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_bound);
RCLCPP_PUBLIC
void
set_bounded_string_value(const std::string & name, const std::string value, size_t string_bound);
RCLCPP_PUBLIC
void
set_bounded_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_bound);
RCLCPP_PUBLIC
void
set_bounded_wstring_value(
const std::string & name, const std::u16string value, size_t wstring_bound);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_bounded_string_value(const std::string value, size_t string_bound);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_bounded_wstring_value(const std::u16string value, size_t wstring_bound);
// NESTED MEMBER ACCESS ==========================================================================
RCLCPP_PUBLIC
DynamicMessage
get_complex_value(rosidl_dynamic_typesupport_member_id_t id);
RCLCPP_PUBLIC
DynamicMessage
get_complex_value(const std::string & name);
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
get_complex_value_shared(rosidl_dynamic_typesupport_member_id_t id);
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
get_complex_value_shared(const std::string & name);
RCLCPP_PUBLIC
void
set_complex_value(rosidl_dynamic_typesupport_member_id_t id, DynamicMessage & value);
RCLCPP_PUBLIC
void
set_complex_value(const std::string & name, DynamicMessage & value);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_complex_value_copy(const DynamicMessage & value);
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_member_id_t
insert_complex_value(DynamicMessage & value);
protected:
// NOTE(methylDragon):
// This is just here to extend the lifetime of the serialization support
// It isn't actually used by the builder since the builder should compose its own support
//
// ... Though ideally it should be the exact same support as the one stored in the
// DynamicSerializationSupport
DynamicSerializationSupport::SharedPtr serialization_support_;
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_data_t> rosidl_dynamic_data_;
bool is_loaned_;
// Used for returning the loaned value, and lifetime management
DynamicMessage::SharedPtr parent_data_;
private:
RCLCPP_PUBLIC
DynamicMessage();
RCLCPP_PUBLIC
bool
match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_data_t & dynamic_data);
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_

View File

@@ -0,0 +1,207 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
class DynamicMessage;
class DynamicMessageTypeBuilder;
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_t *`
/**
* This class:
* - Manages the lifetime of the raw pointer.
* - Exposes getter methods to get the raw pointer and shared pointers
* - Exposes the underlying serialization support API
*
* Ownership:
* - This class borrows the `rosidl_dynamic_typesupport_serialization_support_t` stored in the
* passed `DynamicSerializationSupport`.
* So it cannot outlive the `DynamicSerializationSupport`.
* - The `DynamicSerializationSupport`'s `rosidl_dynamic_typesupport_serialization_support_t`
* pointer must point to the same location in memory as the stored raw pointer!
*
* This class is meant to map to the lower level `rosidl_dynamic_typesupport_dynamic_type_t`,
* which can be constructed via `DynamicMessageTypeBuilder`, which maps to
* `rosidl_dynamic_typesupport_dynamic_type_builder_t`.
*
* The usual method of obtaining a `DynamicMessageType` is through construction of
* `rosidl_message_type_support_t` via `rcl_dynamic_message_type_support_handle_create()`, then
* taking ownership of its contents. But `DynamicMessageTypeBuilder` can also be used to obtain
* `DynamicMessageType` by constructing it bottom-up instead, since it exposes the lower_level
* rosidl methods.
*/
class DynamicMessageType : public std::enable_shared_from_this<DynamicMessageType>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageType)
// CONSTRUCTION ==================================================================================
// Most constructors require a passed in `DynamicSerializationSupport::SharedPtr`, to extend the
// lifetime of the serialization support (if the constructor cannot otherwise get it from args).
//
// In cases where a dynamic type pointer is passed, the serialization support composed by
// the type should be the exact same object managed by the `DynamicSerializationSupport`,
// otherwise the lifetime management will not work properly.
/// Construct a new `DynamicMessageType` with the provided dynamic type builder
RCLCPP_PUBLIC
explicit DynamicMessageType(std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder);
/// Assume ownership of raw pointer
RCLCPP_PUBLIC
DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type);
/// Copy shared pointer
RCLCPP_PUBLIC
DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_t> rosidl_dynamic_type);
/// From description
RCLCPP_PUBLIC
DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description);
/// Copy constructor
RCLCPP_PUBLIC
DynamicMessageType(const DynamicMessageType & other);
/// Move constructor
RCLCPP_PUBLIC
DynamicMessageType(DynamicMessageType && other) noexcept;
/// Copy assignment
RCLCPP_PUBLIC
DynamicMessageType & operator=(const DynamicMessageType & other);
/// Move assignment
RCLCPP_PUBLIC
DynamicMessageType & operator=(DynamicMessageType && other) noexcept;
RCLCPP_PUBLIC
virtual ~DynamicMessageType();
/// Swaps the serialization support if `serialization_support` is populated
RCLCPP_PUBLIC
void
init_from_description(
const rosidl_runtime_c__type_description__TypeDescription & description,
DynamicSerializationSupport::SharedPtr serialization_support = nullptr);
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_library_identifier() const;
RCLCPP_PUBLIC
const std::string
get_name() const;
RCLCPP_PUBLIC
size_t
get_member_count() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_dynamic_type_t *
get_rosidl_dynamic_type();
RCLCPP_PUBLIC
const rosidl_dynamic_typesupport_dynamic_type_t *
get_rosidl_dynamic_type() const;
RCLCPP_PUBLIC
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_t>
get_shared_rosidl_dynamic_type();
RCLCPP_PUBLIC
std::shared_ptr<const rosidl_dynamic_typesupport_dynamic_type_t>
get_shared_rosidl_dynamic_type() const;
RCLCPP_PUBLIC
DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support();
RCLCPP_PUBLIC
DynamicSerializationSupport::ConstSharedPtr
get_shared_dynamic_serialization_support() const;
// METHODS =======================================================================================
RCLCPP_PUBLIC
DynamicMessageType
clone() const;
RCLCPP_PUBLIC
DynamicMessageType::SharedPtr
clone_shared() const;
RCLCPP_PUBLIC
bool
equals(const DynamicMessageType & other) const;
RCLCPP_PUBLIC
DynamicMessage
build_dynamic_message();
RCLCPP_PUBLIC
std::shared_ptr<DynamicMessage>
build_dynamic_message_shared();
protected:
// NOTE(methylDragon):
// This is just here to extend the lifetime of the serialization support
// It isn't actually used by the builder since the builder should compose its own support
//
// ... Though ideally it should be the exact same support as the one stored in the
// `DynamicSerializationSupport`
DynamicSerializationSupport::SharedPtr serialization_support_;
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_t> rosidl_dynamic_type_;
private:
RCLCPP_PUBLIC
DynamicMessageType();
RCLCPP_PUBLIC
bool
match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_type_t & rosidl_dynamic_type);
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_

View File

@@ -0,0 +1,414 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
class DynamicMessage;
class DynamicMessageType;
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_builder_t *`
/**
* This class:
* - Manages the lifetime of the raw pointer.
* - Exposes getter methods to get the raw pointer and shared pointers
* - Exposes the underlying serialization support API
*
* Ownership:
* - This class borrows the rosidl_dynamic_typesupport_serialization_support_t stored in the passed
* `DynamicSerializationSupport`.
* So it cannot outlive the `DynamicSerializationSupport`.
* - The `DynamicSerializationSupport`'s `rosidl_dynamic_typesupport_serialization_support_t`
* pointer must point to the same location in memory as the stored raw pointer!
*
* This class is meant to map to rosidl_dynamic_typesupport_dynamic_type_builder_t, facilitating the
* construction of dynamic types bottom-up in the C++ layer.
*
* The usual method of obtaining a `DynamicMessageType` is through construction of
* `rosidl_message_type_support_t` via `rcl_dynamic_message_type_support_handle_create()`, then
* taking ownership of its contents.
* But `DynamicMessageTypeBuilder` can also be used to obtain `DynamicMessageType` by constructing
* it bottom-up instead, since it exposes the lower_level rosidl methods.
*/
class DynamicMessageTypeBuilder : public std::enable_shared_from_this<DynamicMessageTypeBuilder>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeBuilder)
// CONSTRUCTION ==================================================================================
// All constructors require a passed in `DynamicSerializationSupport::SharedPtr`, to extend the
// lifetime of the serialization support.
//
// In cases where a dynamic type builder pointer is passed, the serialization support composed by
// the builder should be the exact same object managed by the `DynamicSerializationSupport`,
// otherwise the lifetime management will not work properly.
/// Construct a new `DynamicMessageTypeBuilder` with the provided serialization support
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
const std::string & name);
/// Assume ownership of raw pointer
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_type_builder_t * dynamic_type_builder);
/// Copy shared pointer
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_builder_t> dynamic_type_builder);
/// Copy constructor
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(const DynamicMessageTypeBuilder & other);
/// Move constructor
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(DynamicMessageTypeBuilder && other) noexcept;
/// Copy assignment
RCLCPP_PUBLIC
DynamicMessageTypeBuilder & operator=(const DynamicMessageTypeBuilder & other);
/// Move assignment
RCLCPP_PUBLIC
DynamicMessageTypeBuilder & operator=(DynamicMessageTypeBuilder && other) noexcept;
/// From description
RCLCPP_PUBLIC
DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description);
RCLCPP_PUBLIC
virtual ~DynamicMessageTypeBuilder();
/// Swaps the serialization support if serialization_support is populated
RCLCPP_PUBLIC
void
init_from_description(
const rosidl_runtime_c__type_description__TypeDescription & description,
DynamicSerializationSupport::SharedPtr serialization_support = nullptr);
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_library_identifier() const;
RCLCPP_PUBLIC
const std::string
get_name() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_dynamic_type_builder_t *
get_rosidl_dynamic_type_builder();
RCLCPP_PUBLIC
const rosidl_dynamic_typesupport_dynamic_type_builder_t *
get_rosidl_dynamic_type_builder() const;
RCLCPP_PUBLIC
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_builder_t>
get_shared_rosidl_dynamic_type_builder();
RCLCPP_PUBLIC
std::shared_ptr<const rosidl_dynamic_typesupport_dynamic_type_builder_t>
get_shared_rosidl_dynamic_type_builder() const;
RCLCPP_PUBLIC
DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support();
RCLCPP_PUBLIC
DynamicSerializationSupport::ConstSharedPtr
get_shared_dynamic_serialization_support() const;
// METHODS =======================================================================================
RCLCPP_PUBLIC
void
set_name(const std::string & name);
RCLCPP_PUBLIC
DynamicMessageTypeBuilder
clone() const;
RCLCPP_PUBLIC
DynamicMessageTypeBuilder::SharedPtr
clone_shared() const;
RCLCPP_PUBLIC
void
clear();
RCLCPP_PUBLIC
DynamicMessage
build_dynamic_message();
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
build_dynamic_message_shared();
RCLCPP_PUBLIC
DynamicMessageType
build_dynamic_message_type();
RCLCPP_PUBLIC
DynamicMessageType::SharedPtr
build_dynamic_message_type_shared();
// ADD MEMBERS TEMPLATES =========================================================================
/**
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
*
* Explicitly:
* - Basic types: bool, byte, char
* - Float types: float, double
* - Int types: int8_t, int16_t, int32_t, int64_t
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
* - String types: std::string, std::u16string
*/
template<typename MemberT>
void
add_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
const std::string & default_value = "");
template<typename MemberT>
void
add_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t array_length,
const std::string & default_value = "");
template<typename MemberT>
void
add_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
const std::string & default_value = "");
template<typename MemberT>
void
add_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t sequence_bound,
const std::string & default_value = "");
// ADD FIXED STRING MEMBERS ======================================================================
RCLCPP_PUBLIC
void
add_fixed_string_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_wstring_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_string_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_length, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_wstring_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_length, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_string_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_wstring_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_string_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_length, size_t sequence_bound, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_fixed_wstring_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_length, size_t sequence_bound, const std::string & default_value = "");
// ADD BOUNDED STRING MEMBERS ====================================================================
RCLCPP_PUBLIC
void
add_bounded_string_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_wstring_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_string_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_bound, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_wstring_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_bound, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_string_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_wstring_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_string_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_bound, size_t sequence_bound, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_bounded_wstring_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_bound, size_t sequence_bound, const std::string & default_value = "");
// ADD NESTED MEMBERS ============================================================================
RCLCPP_PUBLIC
void
add_complex_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, size_t array_length, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, size_t sequence_bound,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_array_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, size_t array_length,
const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_unbounded_sequence_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value = "");
RCLCPP_PUBLIC
void
add_complex_bounded_sequence_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, size_t sequence_bound,
const std::string & default_value = "");
protected:
// NOTE(methylDragon):
// This is just here to extend the lifetime of the serialization support
// It isn't actually used by the builder since the builder should compose its own support
//
// ... Though ideally it should be the exact same support as the one stored in the
// `DynamicSerializationSupport`
DynamicSerializationSupport::SharedPtr serialization_support_;
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_builder_t> rosidl_dynamic_type_builder_;
private:
RCLCPP_PUBLIC
DynamicMessageTypeBuilder();
RCLCPP_PUBLIC
void
init_from_serialization_support_(
DynamicSerializationSupport::SharedPtr serialization_support,
const std::string & name);
RCLCPP_PUBLIC
bool
match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_type_builder_t & dynamic_type_builder);
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_

View File

@@ -0,0 +1,205 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
#include <rosidl_dynamic_typesupport/dynamic_message_type_support_struct.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <rosidl_runtime_c/message_type_support_struct.h>
#include <rosidl_runtime_c/type_description/type_description__struct.h>
#include <memory>
#include <string>
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
/// Utility wrapper class for `rosidl_message_type_support_t *` containing managed
/// instances of the typesupport handle impl.
/**
*
* NOTE: This class is the recommended way to obtain the dynamic message type
* support struct, instead of `rcl_dynamic_message_type_support_handle_create()`,
* because this class will manage the lifetimes for you.
*
* Do NOT call rcl_dynamic_message_type_support_handle_destroy!!
*
* This class:
* - Manages the lifetime of the raw pointer.
* - Exposes getter methods to get the raw pointer and shared pointers
* - Stores shared pointers to wrapper classes that expose the underlying
* serialization support API
*
* Ownership:
* - This class, similarly to the `rosidl_dynamic_typesupport_serialization_support_t`, must outlive
* all downstream usages of the serialization support.
*/
class DynamicMessageTypeSupport : public std::enable_shared_from_this<DynamicMessageTypeSupport>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeSupport)
// CONSTRUCTION ==================================================================================
/// From description
/// Does NOT take ownership of the description (copies instead.)
/// Constructs type support top-down (calling `rcl_dynamic_message_type_support_handle_create()`)
RCLCPP_PUBLIC
DynamicMessageTypeSupport(
const rosidl_runtime_c__type_description__TypeDescription & description,
const std::string & serialization_library_name = "");
/// From description, for provided serialization support
/// Does NOT take ownership of the description (copies instead.)
/// Constructs type support top-down (calling
/// `rosidl_dynamic_message_type_support_handle_create()`)
RCLCPP_PUBLIC
DynamicMessageTypeSupport(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description);
/// Assume ownership of managed types
/// Does NOT take ownership of the description (copies instead.)
///
/// The serialization support used to construct all managed SharedPtrs must match.
/// The structure of the provided `description` must match the `dynamic_message_type`
/// The structure of the provided `dynamic_message_type` must match the `dynamic_message
///
/// In this case, the user would have constructed the type support bototm-up (by creating the
/// respective dynamic members.)
RCLCPP_PUBLIC
DynamicMessageTypeSupport(
DynamicSerializationSupport::SharedPtr serialization_support,
DynamicMessageType::SharedPtr dynamic_message_type,
DynamicMessage::SharedPtr dynamic_message,
const rosidl_runtime_c__type_description__TypeDescription & description);
RCLCPP_PUBLIC
virtual ~DynamicMessageTypeSupport();
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_library_identifier() const;
RCLCPP_PUBLIC
rosidl_message_type_support_t *
get_rosidl_message_type_support();
RCLCPP_PUBLIC
const rosidl_message_type_support_t *
get_rosidl_message_type_support() const;
RCLCPP_PUBLIC
std::shared_ptr<rosidl_message_type_support_t>
get_shared_rosidl_message_type_support();
RCLCPP_PUBLIC
std::shared_ptr<const rosidl_message_type_support_t>
get_shared_rosidl_message_type_support() const;
RCLCPP_PUBLIC
rosidl_runtime_c__type_description__TypeDescription *
get_rosidl_runtime_c_type_description();
RCLCPP_PUBLIC
const rosidl_runtime_c__type_description__TypeDescription *
get_rosidl_runtime_c_type_description() const;
RCLCPP_PUBLIC
std::shared_ptr<rosidl_runtime_c__type_description__TypeDescription>
get_shared_rosidl_runtime_c_type_description();
RCLCPP_PUBLIC
std::shared_ptr<const rosidl_runtime_c__type_description__TypeDescription>
get_shared_rosidl_runtime_c_type_description() const;
RCLCPP_PUBLIC
DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support();
RCLCPP_PUBLIC
DynamicSerializationSupport::ConstSharedPtr
get_shared_dynamic_serialization_support() const;
RCLCPP_PUBLIC
DynamicMessageType::SharedPtr
get_shared_dynamic_message_type();
RCLCPP_PUBLIC
DynamicMessageType::ConstSharedPtr
get_shared_dynamic_message_type() const;
RCLCPP_PUBLIC
DynamicMessage::SharedPtr
get_shared_dynamic_message();
RCLCPP_PUBLIC
DynamicMessage::ConstSharedPtr
get_shared_dynamic_message() const;
protected:
RCLCPP_DISABLE_COPY(DynamicMessageTypeSupport)
DynamicSerializationSupport::SharedPtr serialization_support_;
DynamicMessageType::SharedPtr dynamic_message_type_;
DynamicMessage::SharedPtr dynamic_message_;
std::shared_ptr<rosidl_runtime_c__type_description__TypeDescription> description_;
std::shared_ptr<rosidl_message_type_support_t> rosidl_message_type_support_;
private:
RCLCPP_PUBLIC
DynamicMessageTypeSupport();
RCLCPP_PUBLIC
void
manage_description_(rosidl_runtime_c__type_description__TypeDescription * description);
RCLCPP_PUBLIC
void
init_dynamic_message_type_(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription * description);
RCLCPP_PUBLIC
void
init_dynamic_message_(DynamicMessageType::SharedPtr dynamic_type);
// By aggregation
RCLCPP_PUBLIC
void
init_rosidl_message_type_support_(
DynamicSerializationSupport::SharedPtr serialization_support,
DynamicMessageType::SharedPtr dynamic_message_type,
DynamicMessage::SharedPtr dynamic_message,
rosidl_runtime_c__type_description__TypeDescription * description);
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_

View File

@@ -0,0 +1,109 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace dynamic_typesupport
{
/// Utility wrapper class for rosidl_dynamic_typesupport_serialization_support_t *
/**
* This class:
* - Manages the lifetime of the raw pointer.
* - Exposes getter methods to get the raw pointer and shared pointers
* - Exposes the underlying serialization support API
*
* Ownership:
* - This class, similarly to the rosidl_dynamic_typesupport_serialization_support_t, must outlive
* all downstream usages of the serialization support.
*/
class DynamicSerializationSupport : public std::enable_shared_from_this<DynamicSerializationSupport>
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicSerializationSupport)
// CONSTRUCTION ==================================================================================
RCLCPP_PUBLIC
DynamicSerializationSupport();
/// Get the rmw middleware implementation specific serialization support (configured by name)
RCLCPP_PUBLIC
explicit DynamicSerializationSupport(const std::string & serialization_library_name);
/// Assume ownership of raw pointer
RCLCPP_PUBLIC
explicit DynamicSerializationSupport(
rosidl_dynamic_typesupport_serialization_support_t * rosidl_serialization_support);
/// Copy shared pointer
RCLCPP_PUBLIC
DynamicSerializationSupport(
std::shared_ptr<rosidl_dynamic_typesupport_serialization_support_t> serialization_support);
/// Move constructor
RCLCPP_PUBLIC
DynamicSerializationSupport(DynamicSerializationSupport && other) noexcept;
/// Move assignment
RCLCPP_PUBLIC
DynamicSerializationSupport & operator=(DynamicSerializationSupport && other) noexcept;
RCLCPP_PUBLIC
virtual ~DynamicSerializationSupport();
// GETTERS =======================================================================================
RCLCPP_PUBLIC
const std::string
get_library_identifier() const;
RCLCPP_PUBLIC
rosidl_dynamic_typesupport_serialization_support_t *
get_rosidl_serialization_support();
RCLCPP_PUBLIC
const rosidl_dynamic_typesupport_serialization_support_t *
get_rosidl_serialization_support() const;
RCLCPP_PUBLIC
std::shared_ptr<rosidl_dynamic_typesupport_serialization_support_t>
get_shared_rosidl_serialization_support();
RCLCPP_PUBLIC
std::shared_ptr<const rosidl_dynamic_typesupport_serialization_support_t>
get_shared_rosidl_serialization_support() const;
protected:
RCLCPP_DISABLE_COPY(DynamicSerializationSupport)
std::shared_ptr<rosidl_dynamic_typesupport_serialization_support_t> rosidl_serialization_support_;
};
} // namespace dynamic_typesupport
} // namespace rclcpp
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_

View File

@@ -0,0 +1,311 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EVENT_HANDLER_HPP_
#define RCLCPP__EVENT_HANDLER_HPP_
#include <functional>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <string>
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
#include "rmw/impl/cpp/demangle.hpp"
#include "rmw/incompatible_qos_events_statuses.h"
#include "rmw/events_statuses/incompatible_type.h"
#include "rcutils/logging_macros.h"
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/function_traits.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
using QOSMessageLostInfo = rmw_message_lost_status_t;
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
using IncompatibleTypeInfo = rmw_incompatible_type_status_t;
using MatchedInfo = rmw_matched_status_t;
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
using QOSRequestedIncompatibleQoSCallbackType =
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
using IncompatibleTypeCallbackType = std::function<void (IncompatibleTypeInfo &)>;
using PublisherMatchedCallbackType = std::function<void (MatchedInfo &)>;
using SubscriptionMatchedCallbackType = std::function<void (MatchedInfo &)>;
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
struct PublisherEventCallbacks
{
QOSDeadlineOfferedCallbackType deadline_callback;
QOSLivelinessLostCallbackType liveliness_callback;
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
IncompatibleTypeCallbackType incompatible_type_callback;
PublisherMatchedCallbackType matched_callback;
};
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
struct SubscriptionEventCallbacks
{
QOSDeadlineRequestedCallbackType deadline_callback;
QOSLivelinessChangedCallbackType liveliness_callback;
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
QOSMessageLostCallbackType message_lost_callback;
IncompatibleTypeCallbackType incompatible_type_callback;
SubscriptionMatchedCallbackType matched_callback;
};
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
{
public:
RCLCPP_PUBLIC
UnsupportedEventTypeException(
rcl_ret_t ret,
const rcl_error_state_t * error_state,
const std::string & prefix);
RCLCPP_PUBLIC
UnsupportedEventTypeException(
const exceptions::RCLErrorBase & base_exc,
const std::string & prefix);
};
class EventHandlerBase : public Waitable
{
public:
enum class EntityType : std::size_t
{
Event,
};
RCLCPP_PUBLIC
virtual ~EventHandlerBase();
/// Get the number of ready events
RCLCPP_PUBLIC
size_t
get_number_of_ready_events() override;
/// Add the Waitable to a wait set.
RCLCPP_PUBLIC
void
add_to_wait_set(rcl_wait_set_t * wait_set) override;
/// Check if the Waitable is ready.
RCLCPP_PUBLIC
bool
is_ready(rcl_wait_set_t * wait_set) override;
/// Set a callback to be called when each new event instance occurs.
/**
* The callback receives a size_t which is the number of events that occurred
* since the last time this callback was called.
* Normally this is 1, but can be > 1 if events occurred before any
* callback was set.
*
* The callback also receives an int identifier argument.
* This is needed because a Waitable may be composed of several distinct entities,
* such as subscriptions, services, etc.
* The application should provide a generic callback function that will be then
* forwarded by the waitable to all of its entities.
* Before forwarding, a different value for the identifier argument will be
* bond to the function.
* This implies that the provided callback can use the identifier to behave
* differently depending on which entity triggered the waitable to become ready.
*
* Since this callback is called from the middleware, you should aim to make
* it fast and not blocking.
* If you need to do a lot of work or wait for some other event, you should
* spin it off to another thread, otherwise you risk blocking the middleware.
*
* Calling it again will clear any previously set callback.
*
* An exception will be thrown if the callback is not callable.
*
* This function is thread-safe.
*
* If you want more information available in the callback, like the qos event
* or other information, you may use a lambda with captures or std::bind.
*
* \sa rmw_event_set_callback
* \sa rcl_event_set_callback
*
* \param[in] callback functor to be called when a new event occurs
*/
void
set_on_ready_callback(std::function<void(size_t, int)> callback) override
{
if (!callback) {
throw std::invalid_argument(
"The callback passed to set_on_ready_callback "
"is not callable.");
}
// Note: we bind the int identifier argument to this waitable's entity types
auto new_callback =
[callback, this](size_t number_of_events) {
try {
callback(number_of_events, static_cast<int>(EntityType::Event));
} catch (const std::exception & exception) {
RCLCPP_ERROR_STREAM(
// TODO(wjwwood): get this class access to the node logger it is associated with
rclcpp::get_logger("rclcpp"),
"rclcpp::EventHandlerBase@" << this <<
" caught " << rmw::impl::cpp::demangle(exception) <<
" exception in user-provided callback for the 'on ready' callback: " <<
exception.what());
} catch (...) {
RCLCPP_ERROR_STREAM(
rclcpp::get_logger("rclcpp"),
"rclcpp::EventHandlerBase@" << this <<
" caught unhandled exception in user-provided callback " <<
"for the 'on ready' callback");
}
};
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
// Set it temporarily to the new callback, while we replace the old one.
// This two-step setting, prevents a gap where the old std::function has
// been replaced but the middleware hasn't been told about the new one yet.
set_on_new_event_callback(
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
static_cast<const void *>(&new_callback));
// Store the std::function to keep it in scope, also overwrites the existing one.
on_new_event_callback_ = new_callback;
// Set it again, now using the permanent storage.
set_on_new_event_callback(
rclcpp::detail::cpp_callback_trampoline<
decltype(on_new_event_callback_), const void *, size_t>,
static_cast<const void *>(&on_new_event_callback_));
}
/// Unset the callback registered for new events, if any.
void
clear_on_ready_callback() override
{
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
if (on_new_event_callback_) {
set_on_new_event_callback(nullptr, nullptr);
on_new_event_callback_ = nullptr;
}
}
protected:
RCLCPP_PUBLIC
void
set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_event_callback_{nullptr};
rcl_event_t event_handle_;
size_t wait_set_event_index_;
};
using QOSEventHandlerBase [[deprecated("Use rclcpp::EventHandlerBase")]] = EventHandlerBase;
template<typename EventCallbackT, typename ParentHandleT>
class EventHandler : public EventHandlerBase
{
public:
template<typename InitFuncT, typename EventTypeEnum>
EventHandler(
const EventCallbackT & callback,
InitFuncT init_func,
ParentHandleT parent_handle,
EventTypeEnum event_type)
: parent_handle_(parent_handle), event_callback_(callback)
{
event_handle_ = rcl_get_zero_initialized_event();
rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_UNSUPPORTED) {
UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
rcl_reset_error();
throw exc;
} else {
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
}
}
}
/// Take data so that the callback cannot be scheduled again
std::shared_ptr<void>
take_data() override
{
EventCallbackInfoT callback_info;
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
if (ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't take event info: %s", rcl_get_error_string().str);
return nullptr;
}
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
}
std::shared_ptr<void>
take_data_by_entity_id(size_t id) override
{
(void)id;
return take_data();
}
/// Execute any entities of the Waitable that are ready.
void
execute(std::shared_ptr<void> & data) override
{
if (!data) {
throw std::runtime_error("'data' is empty");
}
auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
event_callback_(*callback_ptr);
callback_ptr.reset();
}
private:
using EventCallbackInfoT = typename std::remove_reference<typename
rclcpp::function_traits::function_traits<EventCallbackT>::template argument_type<0>>::type;
ParentHandleT parent_handle_;
EventCallbackT event_callback_;
};
template<typename EventCallbackT, typename ParentHandleT>
using QOSEventHandler [[deprecated("Use rclcpp::EventHandler")]] = EventHandler<EventCallbackT,
ParentHandleT>;
} // namespace rclcpp
#endif // RCLCPP__EVENT_HANDLER_HPP_

View File

@@ -315,6 +315,16 @@ public:
virtual void
spin_all(std::chrono::nanoseconds max_duration);
/// Collect work once and execute the next available work, optionally within a duration.
/**
* This function can be overridden. The default implementation is suitable for
* a single-thread model of execution.
* Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
* to block (which may have unintended consequences).
* \param[in] timeout The maximum amount of time to spend waiting for work.
* `-1` is potentially block forever waiting for work.
*/
RCLCPP_PUBLIC
virtual void
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
@@ -413,12 +423,29 @@ public:
is_spinning();
protected:
/// Add a node to executor, execute the next available unit of work, and remove the node.
/**
* Implementation of spin_node_once using std::chrono::nanoseconds
* \param[in] node Shared pointer to the node to add.
* \param[in] timeout How long to wait for work to become available. Negative values cause
* spin_node_once to block indefinitely (the default behavior). A timeout of 0 causes this
* function to be non-blocking.
*/
RCLCPP_PUBLIC
void
spin_node_once_nanoseconds(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
std::chrono::nanoseconds timeout);
/// Collect work and execute available work, optionally within a duration.
/**
* Implementation of spin_some and spin_all.
* The exhaustive flag controls if the function will re-collect available work within the duration.
*
* \param[in] max_duration The maximum amount of time to spend executing work, or 0 for no limit.
* \param[in] exhaustive when set to true, continue to collect work and execute (spin_all)
* when set to false, return when all collected work is executed (spin_some)
*/
RCLCPP_PUBLIC
void
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
@@ -433,30 +460,60 @@ protected:
void
execute_any_executable(AnyExecutable & any_exec);
/// Run subscription executable.
/**
* Do necessary setup and tear-down as well as executing the subscription.
* \param[in] subscription Subscription to execute
*/
RCLCPP_PUBLIC
static void
execute_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription);
/// Run timer executable.
/**
* Do necessary setup and tear-down as well as executing the timer callback.
* \param[in] timer Timer to execute
*/
RCLCPP_PUBLIC
static void
execute_timer(rclcpp::TimerBase::SharedPtr timer);
/// Run service server executable.
/**
* Do necessary setup and tear-down as well as executing the service server callback.
* \param[in] service Service to execute
*/
RCLCPP_PUBLIC
static void
execute_service(rclcpp::ServiceBase::SharedPtr service);
/// Run service client executable.
/**
* Do necessary setup and tear-down as well as executing the service client callback.
* \param[in] service Service to execute
*/
RCLCPP_PUBLIC
static void
execute_client(rclcpp::ClientBase::SharedPtr client);
/// Block until more work becomes avilable or timeout is reached.
/**
* Builds a set of waitable entities, which are passed to the middleware.
* After building wait set, waits on middleware to notify.
* \param[in] timeout duration to wait for new work to become available.
* \throws std::runtime_error if the wait set can be cleared
*/
RCLCPP_PUBLIC
void
wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
/// Find node associated with a callback group
/**
* \param[in] weak_groups_to_nodes map of callback groups to nodes
* \param[in] group callback group to find assocatiated node
* \return Pointer to associated node if found, else nullptr
*/
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_by_group(
@@ -475,6 +532,11 @@ protected:
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
/// Find the callback group associated with a timer
/**
* \param[in] timer Timer to find associated callback group
* \return Pointer to callback group node if found, else nullptr
*/
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
@@ -502,16 +564,54 @@ protected:
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
/// Check for executable in ready state and populate union structure.
/**
* \param[out] any_executable populated union structure of ready executable
* \return true if an executable was ready and any_executable was populated,
* otherwise false
*/
RCLCPP_PUBLIC
bool
get_next_ready_executable(AnyExecutable & any_executable);
/// Check for executable in ready state and populate union structure.
/**
* This is the implementation of get_next_ready_executable that takes into
* account the current state of callback groups' association with nodes and
* executors.
*
* This checks in a particular order for available work:
* * Timers
* * Subscriptions
* * Services
* * Clients
* * Waitable
*
* If the next executable is not associated with this executor/node pair,
* then this method will return false.
*
* \param[out] any_executable populated union structure of ready executable
* \param[in] weak_groups_to_nodes mapping of callback groups to nodes
* \return true if an executable was ready and any_executable was populated,
* otherwise false
*/
RCLCPP_PUBLIC
bool
get_next_ready_executable_from_map(
AnyExecutable & any_executable,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
/// Wait for executable in ready state and populate union structure.
/**
* If an executable is ready, it will return immediately, otherwise
* block based on the timeout for work to become ready.
*
* \param[out] any_executable populated union structure of ready executable
* \param[in] timeout duration of time to wait for work, a negative value
* (the defualt behavior), will make this function block indefinitely
* \return true if an executable was ready and any_executable was populated,
* otherwise false
*/
RCLCPP_PUBLIC
bool
get_next_executable(

View File

@@ -454,6 +454,8 @@ private:
if (std::next(it) == subscription_ids.end()) {
// If this is the last subscription, give up ownership
subscription->provide_intra_process_data(std::move(message));
// Last message delivered, break from for loop
break;
} else {
// Copy the message since we have additional subscriptions to serve
Deleter deleter = message.get_deleter();
@@ -493,6 +495,8 @@ private:
if (std::next(it) == subscription_ids.end()) {
// If this is the last subscription, give up ownership
ros_message_subscription->provide_intra_process_message(std::move(message));
// Last message delivered, break from for loop
break;
} else {
// Copy the message since we have additional subscriptions to serve
Deleter deleter = message.get_deleter();

View File

@@ -84,7 +84,7 @@ public:
options.to_rcl_subscription_options(qos),
options.event_callbacks,
options.use_default_callbacks,
true),
SubscriptionType::SERIALIZED_MESSAGE),
callback_(callback),
ts_lib_(ts_lib)
{}
@@ -123,6 +123,32 @@ public:
RCLCPP_PUBLIC
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
// DYNAMIC TYPE ==================================================================================
// TODO(methylDragon): Reorder later
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr get_shared_dynamic_message_type()
override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr get_shared_dynamic_message() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support() override;
RCLCPP_PUBLIC
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override;
RCLCPP_PUBLIC
void return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override;
RCLCPP_PUBLIC
void handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info) override;
private:
RCLCPP_DISABLE_COPY(GenericSubscription)

View File

@@ -17,6 +17,7 @@
#include <memory>
#include <string>
#include <utility>
#include "rclcpp/visibility_control.hpp"
@@ -122,6 +123,7 @@ private:
: name_(new std::string(name)) {}
std::shared_ptr<const std::string> name_;
std::shared_ptr<std::pair<std::string, std::string>> logger_sublogger_pairname_ = nullptr;
public:
RCLCPP_PUBLIC
@@ -157,13 +159,7 @@ public:
*/
RCLCPP_PUBLIC
Logger
get_child(const std::string & suffix)
{
if (!name_) {
return Logger();
}
return Logger(*name_ + "." + suffix);
}
get_child(const std::string & suffix);
/// Set level for current logger.
/**
@@ -174,6 +170,24 @@ public:
RCLCPP_PUBLIC
void
set_level(Level level);
/// Get effective level for current logger.
/**
* The effective level is determined as the severity level of
* the logger if it is set, otherwise it is the first specified severity
* level of the logger's ancestors, starting with its closest ancestor.
* The ancestor hierarchy is signified by logger names being separated by dots:
* a logger named `x` is an ancestor of `x.y`, and both `x` and `x.y` are
* ancestors of `x.y.z`, etc.
* If the level has not been set for the logger nor any of its
* ancestors, the default level is used.
*
* \throws rclcpp::exceptions::RCLError if any error happens.
* \return Level for the current logger.
*/
RCLCPP_PUBLIC
Level
get_effective_level() const;
};
} // namespace rclcpp

View File

@@ -381,10 +381,6 @@ public:
if (!loaned_msg.is_valid()) {
throw std::runtime_error("loaned message is not valid");
}
if (intra_process_is_enabled_) {
// TODO(Karsten1987): support loaned message passed by intraprocess
throw std::runtime_error("storing loaned messages in intra process is not supported yet");
}
// verify that publisher supports loaned messages
// TODO(Karsten1987): This case separation has to be done in rclcpp
@@ -398,7 +394,7 @@ public:
} else {
// we don't release the ownership, let the middleware copy the ros message
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
this->do_inter_process_publish(loaned_msg.get());
this->publish(loaned_msg.get());
}
}

View File

@@ -33,7 +33,7 @@
#include "rclcpp/macros.hpp"
#include "rclcpp/network_flow_endpoint.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/event_handler.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcpputils/time.hpp"
@@ -124,7 +124,7 @@ public:
/** \return The map of QoS event handlers. */
RCLCPP_PUBLIC
const
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
get_event_handlers() const;
/// Get subscription count
@@ -276,7 +276,7 @@ public:
* If you want more information available in the callback, like the qos event
* or other information, you may use a lambda with captures or std::bind.
*
* \sa rclcpp::QOSEventHandlerBase::set_on_ready_callback
* \sa rclcpp::EventHandlerBase::set_on_ready_callback
*
* \param[in] callback functor to be called when a new event occurs
* \param[in] event_type identifier for the qos event we want to attach the callback to
@@ -327,7 +327,7 @@ protected:
const EventCallbackT & callback,
const rcl_publisher_event_type_t event_type)
{
auto handler = std::make_shared<QOSEventHandler<EventCallbackT,
auto handler = std::make_shared<EventHandler<EventCallbackT,
std::shared_ptr<rcl_publisher_t>>>(
callback,
rcl_publisher_event_init,
@@ -339,12 +339,15 @@ protected:
RCLCPP_PUBLIC
void default_incompatible_qos_callback(QOSOfferedIncompatibleQoSInfo & info) const;
RCLCPP_PUBLIC
void default_incompatible_type_callback(IncompatibleTypeInfo & info) const;
std::shared_ptr<rcl_node_t> rcl_node_handle_;
std::shared_ptr<rcl_publisher_t> publisher_handle_;
std::unordered_map<rcl_publisher_event_type_t,
std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
std::shared_ptr<rclcpp::EventHandlerBase>> event_handlers_;
using IntraProcessManagerWeakPtr =
std::weak_ptr<rclcpp::experimental::IntraProcessManager>;

View File

@@ -26,7 +26,7 @@
#include "rclcpp/detail/rmw_implementation_specific_publisher_payload.hpp"
#include "rclcpp/intra_process_setting.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/event_handler.hpp"
#include "rclcpp/qos_overriding_options.hpp"
namespace rclcpp

View File

@@ -15,278 +15,8 @@
#ifndef RCLCPP__QOS_EVENT_HPP_
#define RCLCPP__QOS_EVENT_HPP_
#include <functional>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <string>
#warning This header is obsolete, please include rclcpp/event_handler.hpp instead
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
#include "rmw/impl/cpp/demangle.hpp"
#include "rmw/incompatible_qos_events_statuses.h"
#include "rcutils/logging_macros.h"
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/function_traits.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
using QOSMessageLostInfo = rmw_message_lost_status_t;
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
using QOSRequestedIncompatibleQoSCallbackType =
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
struct PublisherEventCallbacks
{
QOSDeadlineOfferedCallbackType deadline_callback;
QOSLivelinessLostCallbackType liveliness_callback;
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
};
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
struct SubscriptionEventCallbacks
{
QOSDeadlineRequestedCallbackType deadline_callback;
QOSLivelinessChangedCallbackType liveliness_callback;
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
QOSMessageLostCallbackType message_lost_callback;
};
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
{
public:
RCLCPP_PUBLIC
UnsupportedEventTypeException(
rcl_ret_t ret,
const rcl_error_state_t * error_state,
const std::string & prefix);
RCLCPP_PUBLIC
UnsupportedEventTypeException(
const exceptions::RCLErrorBase & base_exc,
const std::string & prefix);
};
class QOSEventHandlerBase : public Waitable
{
public:
enum class EntityType : std::size_t
{
Event,
};
RCLCPP_PUBLIC
virtual ~QOSEventHandlerBase();
/// Get the number of ready events
RCLCPP_PUBLIC
size_t
get_number_of_ready_events() override;
/// Add the Waitable to a wait set.
RCLCPP_PUBLIC
void
add_to_wait_set(rcl_wait_set_t * wait_set) override;
/// Check if the Waitable is ready.
RCLCPP_PUBLIC
bool
is_ready(rcl_wait_set_t * wait_set) override;
/// Set a callback to be called when each new event instance occurs.
/**
* The callback receives a size_t which is the number of events that occurred
* since the last time this callback was called.
* Normally this is 1, but can be > 1 if events occurred before any
* callback was set.
*
* The callback also receives an int identifier argument.
* This is needed because a Waitable may be composed of several distinct entities,
* such as subscriptions, services, etc.
* The application should provide a generic callback function that will be then
* forwarded by the waitable to all of its entities.
* Before forwarding, a different value for the identifier argument will be
* bond to the function.
* This implies that the provided callback can use the identifier to behave
* differently depending on which entity triggered the waitable to become ready.
*
* Since this callback is called from the middleware, you should aim to make
* it fast and not blocking.
* If you need to do a lot of work or wait for some other event, you should
* spin it off to another thread, otherwise you risk blocking the middleware.
*
* Calling it again will clear any previously set callback.
*
* An exception will be thrown if the callback is not callable.
*
* This function is thread-safe.
*
* If you want more information available in the callback, like the qos event
* or other information, you may use a lambda with captures or std::bind.
*
* \sa rmw_event_set_callback
* \sa rcl_event_set_callback
*
* \param[in] callback functor to be called when a new event occurs
*/
void
set_on_ready_callback(std::function<void(size_t, int)> callback) override
{
if (!callback) {
throw std::invalid_argument(
"The callback passed to set_on_ready_callback "
"is not callable.");
}
// Note: we bind the int identifier argument to this waitable's entity types
auto new_callback =
[callback, this](size_t number_of_events) {
try {
callback(number_of_events, static_cast<int>(EntityType::Event));
} catch (const std::exception & exception) {
RCLCPP_ERROR_STREAM(
// TODO(wjwwood): get this class access to the node logger it is associated with
rclcpp::get_logger("rclcpp"),
"rclcpp::QOSEventHandlerBase@" << this <<
" caught " << rmw::impl::cpp::demangle(exception) <<
" exception in user-provided callback for the 'on ready' callback: " <<
exception.what());
} catch (...) {
RCLCPP_ERROR_STREAM(
rclcpp::get_logger("rclcpp"),
"rclcpp::QOSEventHandlerBase@" << this <<
" caught unhandled exception in user-provided callback " <<
"for the 'on ready' callback");
}
};
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
// Set it temporarily to the new callback, while we replace the old one.
// This two-step setting, prevents a gap where the old std::function has
// been replaced but the middleware hasn't been told about the new one yet.
set_on_new_event_callback(
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
static_cast<const void *>(&new_callback));
// Store the std::function to keep it in scope, also overwrites the existing one.
on_new_event_callback_ = new_callback;
// Set it again, now using the permanent storage.
set_on_new_event_callback(
rclcpp::detail::cpp_callback_trampoline<
decltype(on_new_event_callback_), const void *, size_t>,
static_cast<const void *>(&on_new_event_callback_));
}
/// Unset the callback registered for new events, if any.
void
clear_on_ready_callback() override
{
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
if (on_new_event_callback_) {
set_on_new_event_callback(nullptr, nullptr);
on_new_event_callback_ = nullptr;
}
}
protected:
RCLCPP_PUBLIC
void
set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
rcl_event_t event_handle_;
size_t wait_set_event_index_;
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_event_callback_{nullptr};
};
template<typename EventCallbackT, typename ParentHandleT>
class QOSEventHandler : public QOSEventHandlerBase
{
public:
template<typename InitFuncT, typename EventTypeEnum>
QOSEventHandler(
const EventCallbackT & callback,
InitFuncT init_func,
ParentHandleT parent_handle,
EventTypeEnum event_type)
: parent_handle_(parent_handle), event_callback_(callback)
{
event_handle_ = rcl_get_zero_initialized_event();
rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_UNSUPPORTED) {
UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
rcl_reset_error();
throw exc;
} else {
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
}
}
}
/// Take data so that the callback cannot be scheduled again
std::shared_ptr<void>
take_data() override
{
EventCallbackInfoT callback_info;
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
if (ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't take event info: %s", rcl_get_error_string().str);
return nullptr;
}
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
}
std::shared_ptr<void>
take_data_by_entity_id(size_t id) override
{
(void)id;
return take_data();
}
/// Execute any entities of the Waitable that are ready.
void
execute(std::shared_ptr<void> & data) override
{
if (!data) {
throw std::runtime_error("'data' is empty");
}
auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
event_callback_(*callback_ptr);
callback_ptr.reset();
}
private:
using EventCallbackInfoT = typename std::remove_reference<typename
rclcpp::function_traits::function_traits<EventCallbackT>::template argument_type<0>>::type;
ParentHandleT parent_handle_;
EventCallbackT event_callback_;
};
} // namespace rclcpp
#include "rclcpp/event_handler.hpp"
#endif // RCLCPP__QOS_EVENT_HPP_

View File

@@ -117,6 +117,21 @@
* - Allocator related items:
* - rclcpp/allocator/allocator_common.hpp
* - rclcpp/allocator/allocator_deleter.hpp
* - Dynamic typesupport wrappers
* - rclcpp::dynamic_typesupport::DynamicMessage
* - rclcpp::dynamic_typesupport::DynamicMessageType
* - rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder
* - rclcpp::dynamic_typesupport::DynamicSerializationSupport
* - rclcpp/dynamic_typesupport/dynamic_message.hpp
* - rclcpp/dynamic_typesupport/dynamic_message_type.hpp
* - rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp
* - rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp
* - Dynamic typesupport
* - rclcpp::dynamic_typesupport::DynamicMessageTypeSupport
* - rclcpp/dynamic_typesupport/dynamic_message_type_support.hpp
* - Dynamic subscription
* - rclcpp::DynamicSubscription
* - rclcpp/dynamic_subscription.hpp
* - Generic publisher
* - rclcpp::Node::create_generic_publisher()
* - rclcpp::GenericPublisher
@@ -167,4 +182,6 @@
#include "rclcpp/waitable.hpp"
#include "rclcpp/wait_set.hpp"
#include "rclcpp/dynamic_subscription.hpp"
#endif // RCLCPP__RCLCPP_HPP_

View File

@@ -1,56 +0,0 @@
// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Based on: http://the-witness.net/news/2012/11/scopeexit-in-c11/
// But I changed the lambda to include by reference rather than value, see:
// http://the-witness.net/news/2012/11/scopeexit-in-c11/comment-page-1/#comment-86873
#ifndef RCLCPP__SCOPE_EXIT_HPP_
#define RCLCPP__SCOPE_EXIT_HPP_
// TODO(christophebedard) remove this header completely in I-turtle
#warning rclcpp/scope_exit.hpp has been deprecated, please use rcpputils/scope_exit.hpp instead
#include <functional>
#include "rclcpp/macros.hpp"
namespace rclcpp
{
template<typename Callable>
struct ScopeExit
{
explicit ScopeExit(Callable callable)
: callable_(callable) {}
~ScopeExit() {callable_();}
private:
Callable callable_;
};
template<typename Callable>
ScopeExit<Callable>
make_scope_exit(Callable callable)
{
return ScopeExit<Callable>(callable);
}
} // namespace rclcpp
#define RCLCPP_SCOPE_EXIT(code) \
auto RCLCPP_STRING_JOIN(scope_exit_, __LINE__) = rclcpp::make_scope_exit([&]() {code;})
#endif // RCLCPP__SCOPE_EXIT_HPP_

View File

@@ -26,6 +26,7 @@
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
#include "rcl/service.h"
#include "rcl/service_introspection.h"
#include "rmw/error_handling.h"
#include "rmw/impl/cpp/demangle.hpp"
@@ -34,6 +35,7 @@
#include "tracetools/tracetools.h"
#include "rclcpp/any_service_callback.hpp"
#include "rclcpp/clock.hpp"
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
@@ -308,11 +310,9 @@ public:
const std::string & service_name,
AnyServiceCallback<ServiceT> any_callback,
rcl_service_options_t & service_options)
: ServiceBase(node_handle), any_callback_(any_callback)
: ServiceBase(node_handle), any_callback_(any_callback),
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
{
using rosidl_typesupport_cpp::get_service_type_support_handle;
auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
// rcl does the static memory allocation here
service_handle_ = std::shared_ptr<rcl_service_t>(
new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
@@ -331,7 +331,7 @@ public:
rcl_ret_t ret = rcl_service_init(
service_handle_.get(),
node_handle.get(),
service_type_support_handle,
srv_type_support_handle_,
service_name.c_str(),
&service_options);
if (ret != RCL_RET_OK) {
@@ -371,8 +371,8 @@ public:
std::shared_ptr<rcl_node_t> node_handle,
std::shared_ptr<rcl_service_t> service_handle,
AnyServiceCallback<ServiceT> any_callback)
: ServiceBase(node_handle),
any_callback_(any_callback)
: ServiceBase(node_handle), any_callback_(any_callback),
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
{
// check if service handle was initialized
if (!rcl_service_is_valid(service_handle.get())) {
@@ -406,8 +406,8 @@ public:
std::shared_ptr<rcl_node_t> node_handle,
rcl_service_t * service_handle,
AnyServiceCallback<ServiceT> any_callback)
: ServiceBase(node_handle),
any_callback_(any_callback)
: ServiceBase(node_handle), any_callback_(any_callback),
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
{
// check if service handle was initialized
if (!rcl_service_is_valid(service_handle)) {
@@ -487,10 +487,39 @@ public:
}
}
/// Configure client introspection.
/**
* \param[in] clock clock to use to generate introspection timestamps
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
* \param[in] introspection_state the state to set introspection to
*/
void
configure_introspection(
Clock::SharedPtr clock, const QoS & qos_service_event_pub,
rcl_service_introspection_state_t introspection_state)
{
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
rcl_ret_t ret = rcl_service_configure_service_introspection(
service_handle_.get(),
node_handle_.get(),
clock->get_clock_handle(),
srv_type_support_handle_,
pub_opts,
introspection_state);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure service introspection");
}
}
private:
RCLCPP_DISABLE_COPY(Service)
AnyServiceCallback<ServiceT> any_callback_;
const rosidl_service_type_support_t * srv_type_support_handle_;
};
} // namespace rclcpp

View File

@@ -17,6 +17,7 @@
#include <memory>
#include <vector>
#include <utility>
#include "rcl/allocator.h"
@@ -120,8 +121,8 @@ public:
}
}
for (size_t i = 0; i < waitable_handles_.size(); ++i) {
if (!waitable_handles_[i]->is_ready(wait_set)) {
waitable_handles_[i].reset();
if (waitable_handles_[i]->is_ready(wait_set)) {
waitable_triggered_handles_.emplace_back(std::move(waitable_handles_[i]));
}
}
@@ -145,10 +146,7 @@ public:
timer_handles_.end()
);
waitable_handles_.erase(
std::remove(waitable_handles_.begin(), waitable_handles_.end(), nullptr),
waitable_handles_.end()
);
waitable_handles_.clear();
}
bool collect_entities(const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
@@ -392,8 +390,9 @@ public:
rclcpp::AnyExecutable & any_exec,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
{
auto it = waitable_handles_.begin();
while (it != waitable_handles_.end()) {
auto & waitable_handles = waitable_triggered_handles_;
auto it = waitable_handles.begin();
while (it != waitable_handles.end()) {
std::shared_ptr<Waitable> & waitable = *it;
if (waitable) {
// Find the group for this handle and see if it can be serviced
@@ -401,7 +400,7 @@ public:
if (!group) {
// Group was not found, meaning the waitable is not valid...
// Remove it from the ready list and continue looking
it = waitable_handles_.erase(it);
it = waitable_handles.erase(it);
continue;
}
if (!group->can_be_taken_from().load()) {
@@ -414,11 +413,11 @@ public:
any_exec.waitable = waitable;
any_exec.callback_group = group;
any_exec.node_base = get_node_by_group(group, weak_groups_to_nodes);
waitable_handles_.erase(it);
waitable_handles.erase(it);
return;
}
// Else, the waitable is no longer valid, remove it and continue
it = waitable_handles_.erase(it);
it = waitable_handles.erase(it);
}
}
@@ -499,6 +498,8 @@ private:
VectorRebind<std::shared_ptr<const rcl_timer_t>> timer_handles_;
VectorRebind<std::shared_ptr<Waitable>> waitable_handles_;
VectorRebind<std::shared_ptr<Waitable>> waitable_triggered_handles_;
std::shared_ptr<VoidAlloc> allocator_;
};

View File

@@ -144,7 +144,7 @@ public:
// NOTE(methylDragon): Passing these args separately is necessary for event binding
options.event_callbacks,
options.use_default_callbacks,
callback.is_serialized_message_callback()),
callback.is_serialized_message_callback() ? SubscriptionType::SERIALIZED_MESSAGE : SubscriptionType::ROS_MESSAGE), // NOLINT
any_callback_(callback),
options_(options),
message_memory_strategy_(message_memory_strategy)
@@ -388,6 +388,57 @@ public:
return any_callback_.use_take_shared_method();
}
// DYNAMIC TYPE ==================================================================================
// TODO(methylDragon): Reorder later
// TODO(methylDragon): Implement later...
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
get_shared_dynamic_message_type() override
{
throw rclcpp::exceptions::UnimplementedError(
"get_shared_dynamic_message_type is not implemented for Subscription");
}
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
get_shared_dynamic_message() override
{
throw rclcpp::exceptions::UnimplementedError(
"get_shared_dynamic_message is not implemented for Subscription");
}
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support() override
{
throw rclcpp::exceptions::UnimplementedError(
"get_shared_dynamic_serialization_support is not implemented for Subscription");
}
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
create_dynamic_message() override
{
throw rclcpp::exceptions::UnimplementedError(
"create_dynamic_message is not implemented for Subscription");
}
void
return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override
{
(void) message;
throw rclcpp::exceptions::UnimplementedError(
"return_dynamic_message is not implemented for Subscription");
}
void
handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info) override
{
(void) message;
(void) message_info;
throw rclcpp::exceptions::UnimplementedError(
"handle_dynamic_message is not implemented for Subscription");
}
private:
RCLCPP_DISABLE_COPY(Subscription)

View File

@@ -31,13 +31,16 @@
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/experimental/intra_process_manager.hpp"
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/message_info.hpp"
#include "rclcpp/network_flow_endpoint.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/event_handler.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/subscription_content_filter_options.hpp"
#include "rclcpp/type_support_decl.hpp"
@@ -60,6 +63,14 @@ namespace experimental
class IntraProcessManager;
} // namespace experimental
enum class SubscriptionType : uint8_t
{
ROS_MESSAGE = 1, // take message as ROS message and handle as ROS message
SERIALIZED_MESSAGE = 2, // take message as serialized and handle as serialized
DYNAMIC_MESSAGE_DIRECT = 3, // take message as DynamicMessage and handle as DynamicMessage
DYNAMIC_MESSAGE_FROM_SERIALIZED = 4 // take message as serialized and handle as DynamicMessage
};
/// Virtual base class for subscriptions. This pattern allows us to iterate over different template
/// specializations of Subscription, among other things.
class SubscriptionBase : public std::enable_shared_from_this<SubscriptionBase>
@@ -76,7 +87,7 @@ public:
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
* \param[in] topic_name Name of the topic to subscribe to.
* \param[in] subscription_options Options for the subscription.
* \param[in] is_serialized is true if the message will be delivered still serialized
* \param[in] subscription_type Enum flag to change how the message will be received and delivered
*/
RCLCPP_PUBLIC
SubscriptionBase(
@@ -86,7 +97,7 @@ public:
const rcl_subscription_options_t & subscription_options,
const SubscriptionEventCallbacks & event_callbacks,
bool use_default_callbacks,
bool is_serialized = false);
SubscriptionType subscription_type = SubscriptionType::ROS_MESSAGE);
/// Destructor.
RCLCPP_PUBLIC
@@ -115,7 +126,7 @@ public:
/** \return The map of QoS event handlers. */
RCLCPP_PUBLIC
const
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
get_event_handlers() const;
/// Get the actual QoS settings, after the defaults have been determined.
@@ -227,13 +238,13 @@ public:
const rosidl_message_type_support_t &
get_message_type_support_handle() const;
/// Return if the subscription is serialized
/// Return the type of the subscription.
/**
* \return `true` if the subscription is serialized, `false` otherwise
* \return `SubscriptionType`, which adjusts how messages are received and delivered.
*/
RCLCPP_PUBLIC
bool
is_serialized() const;
SubscriptionType
get_subscription_type() const;
/// Get matching publisher count.
/** \return The number of publishers on this topic. */
@@ -457,7 +468,7 @@ public:
* If you want more information available in the callback, like the qos event
* or other information, you may use a lambda with captures or std::bind.
*
* \sa rclcpp::QOSEventHandlerBase::set_on_ready_callback
* \sa rclcpp::EventHandlerBase::set_on_ready_callback
*
* \param[in] callback functor to be called when a new event occurs
* \param[in] event_type identifier for the qos event we want to attach the callback to
@@ -535,6 +546,49 @@ public:
rclcpp::ContentFilterOptions
get_content_filter() const;
// DYNAMIC TYPE ==================================================================================
// TODO(methylDragon): Reorder later
RCLCPP_PUBLIC
virtual
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
get_shared_dynamic_message_type() = 0;
RCLCPP_PUBLIC
virtual
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
get_shared_dynamic_message() = 0;
RCLCPP_PUBLIC
virtual
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
get_shared_dynamic_serialization_support() = 0;
/// Borrow a new serialized message (this clones!)
/** \return Shared pointer to a rclcpp::dynamic_typesupport::DynamicMessage. */
RCLCPP_PUBLIC
virtual
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
create_dynamic_message() = 0;
RCLCPP_PUBLIC
virtual
void
return_dynamic_message(rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) = 0;
RCLCPP_PUBLIC
virtual
void
handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info) = 0;
RCLCPP_PUBLIC
bool
take_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage & message_out,
rclcpp::MessageInfo & message_info_out);
// ===============================================================================================
protected:
template<typename EventCallbackT>
void
@@ -542,7 +596,7 @@ protected:
const EventCallbackT & callback,
const rcl_subscription_event_type_t event_type)
{
auto handler = std::make_shared<QOSEventHandler<EventCallbackT,
auto handler = std::make_shared<EventHandler<EventCallbackT,
std::shared_ptr<rcl_subscription_t>>>(
callback,
rcl_subscription_event_init,
@@ -555,6 +609,9 @@ protected:
RCLCPP_PUBLIC
void default_incompatible_qos_callback(QOSRequestedIncompatibleQoSInfo & info) const;
RCLCPP_PUBLIC
void default_incompatible_type_callback(IncompatibleTypeInfo & info) const;
RCLCPP_PUBLIC
bool
matches_any_intra_process_publishers(const rmw_gid_t * sender_gid) const;
@@ -565,13 +622,17 @@ protected:
rclcpp::node_interfaces::NodeBaseInterface * const node_base_;
// TODO(methylDragon): Remove if we don't need this
// rclcpp::node_interfaces::NodeGraphInterface * const node_graph_;
// rclcpp::node_interfaces::NodeServicesInterface * const node_services_;
std::shared_ptr<rcl_node_t> node_handle_;
std::shared_ptr<rcl_subscription_t> subscription_handle_;
std::shared_ptr<rcl_subscription_t> intra_process_subscription_handle_;
rclcpp::Logger node_logger_;
std::unordered_map<rcl_subscription_event_type_t,
std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
std::shared_ptr<rclcpp::EventHandlerBase>> event_handlers_;
bool use_intra_process_;
IntraProcessManagerWeakPtr weak_ipm_;
@@ -584,11 +645,11 @@ private:
RCLCPP_DISABLE_COPY(SubscriptionBase)
rosidl_message_type_support_t type_support_;
bool is_serialized_;
SubscriptionType subscription_type_;
std::atomic<bool> subscription_in_use_by_wait_set_{false};
std::atomic<bool> intra_process_subscription_waitable_in_use_by_wait_set_{false};
std::unordered_map<rclcpp::QOSEventHandlerBase *,
std::unordered_map<rclcpp::EventHandlerBase *,
std::atomic<bool>> qos_events_in_use_by_wait_set_;
std::recursive_mutex callback_mutex_;

View File

@@ -26,7 +26,7 @@
#include "rclcpp/intra_process_buffer_type.hpp"
#include "rclcpp/intra_process_setting.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/event_handler.hpp"
#include "rclcpp/qos_overriding_options.hpp"
#include "rclcpp/subscription_content_filter_options.hpp"
#include "rclcpp/topic_statistics_state.hpp"

View File

@@ -227,10 +227,16 @@ public:
rclcpp_timer_callback_added,
static_cast<const void *>(get_timer_handle().get()),
reinterpret_cast<const void *>(&callback_));
TRACEPOINT(
rclcpp_callback_register,
reinterpret_cast<const void *>(&callback_),
tracetools::get_symbol(callback_));
#ifndef TRACETOOLS_DISABLED
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
char * symbol = tracetools::get_symbol(callback_);
DO_TRACEPOINT(
rclcpp_callback_register,
reinterpret_cast<const void *>(&callback_),
symbol);
std::free(symbol);
}
#endif
}
/// Default destructor.

View File

@@ -516,7 +516,7 @@ public:
* the waitable to be removed, but it will cause the associated entity pointer
* to be nullptr when introspecting this waitable after waiting.
*
* Note that rclcpp::QOSEventHandlerBase are just a special case of
* Note that rclcpp::EventHandlerBase is just a special case of
* rclcpp::Waitable and can be added with this function.
*
* \param[in] waitable Waitable to be added.

View File

@@ -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>19.1.0</version>
<version>19.3.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
@@ -39,6 +39,7 @@
<depend>rcpputils</depend>
<depend>rcutils</depend>
<depend>rmw</depend>
<depend>rosidl_dynamic_typesupport</depend>
<depend>statistics_msgs</depend>
<depend>tracetools</depend>

View File

@@ -23,9 +23,11 @@
#include "rcl/graph.h"
#include "rcl/node.h"
#include "rcl/wait.h"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/logging.hpp"
@@ -241,7 +243,6 @@ ClientBase::set_on_new_response_callback(rcl_event_callback_t callback, const vo
user_data);
if (RCL_RET_OK != ret) {
using rclcpp::exceptions::throw_from_rcl_error;
throw_from_rcl_error(ret, "failed to set the on new response callback for client");
}
}

View File

@@ -219,7 +219,7 @@ Context::init(
if (0u == count) {
ret = rcl_logging_configure_with_output_handler(
&rcl_context_->global_arguments,
rcl_init_options_get_allocator(init_options_.get_rcl_init_options()),
rcl_init_options_get_allocator(init_options.get_rcl_init_options()),
rclcpp_logging_output_handler);
if (RCL_RET_OK != ret) {
rcl_context_.reset();

View File

@@ -0,0 +1,113 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "rclcpp/dynamic_subscription.hpp"
#include <memory>
#include <string>
#include "rcl/subscription.h"
#include "rclcpp/exceptions.hpp"
namespace rclcpp
{
std::shared_ptr<void> DynamicSubscription::create_message()
{
return create_serialized_message();
}
std::shared_ptr<rclcpp::SerializedMessage> DynamicSubscription::create_serialized_message()
{
return std::make_shared<rclcpp::SerializedMessage>(0);
}
void DynamicSubscription::handle_message(std::shared_ptr<void> &, const rclcpp::MessageInfo &)
{
throw rclcpp::exceptions::UnimplementedError(
"handle_message is not implemented for DynamicSubscription");
}
void DynamicSubscription::handle_serialized_message(
const std::shared_ptr<rclcpp::SerializedMessage> &, const rclcpp::MessageInfo &)
{
throw rclcpp::exceptions::UnimplementedError(
"handle_serialized_message is not implemented for DynamicSubscription");
}
void DynamicSubscription::handle_loaned_message(void *, const rclcpp::MessageInfo &)
{
throw rclcpp::exceptions::UnimplementedError(
"handle_loaned_message is not implemented for DynamicSubscription");
}
void DynamicSubscription::return_message(std::shared_ptr<void> & message)
{
auto typed_message = std::static_pointer_cast<rclcpp::SerializedMessage>(message);
return_serialized_message(typed_message);
}
void DynamicSubscription::return_serialized_message(
std::shared_ptr<rclcpp::SerializedMessage> & message)
{
message.reset();
}
// DYNAMIC TYPE ====================================================================================
// TODO(methylDragon): Re-order later
// Does not clone
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
DynamicSubscription::get_shared_dynamic_message_type()
{
return dynamic_message_type_;
}
// Does not clone
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
DynamicSubscription::get_shared_dynamic_message()
{
return dynamic_message_;
}
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
DynamicSubscription::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
DynamicSubscription::create_dynamic_message()
{
return dynamic_message_->init_from_type_shared(*dynamic_message_type_);
}
void
DynamicSubscription::return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
{
message.reset();
}
void DynamicSubscription::handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info)
{
(void) message_info;
callback_(message, ts_->get_shared_rosidl_runtime_c_type_description());
}
} // namespace rclcpp

View File

@@ -0,0 +1,838 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rcl/types.h"
#include "rcutils/logging_macros.h"
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/exceptions.hpp"
using rclcpp::dynamic_typesupport::DynamicMessage;
using rclcpp::dynamic_typesupport::DynamicMessageType;
using rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder;
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
// Template specialization implementations
#include "rclcpp/dynamic_typesupport/detail/dynamic_message_impl.hpp"
#endif
// CONSTRUCTION ==================================================================================
DynamicMessage::DynamicMessage(const DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder)
: serialization_support_(dynamic_type_builder->get_shared_dynamic_serialization_support()),
rosidl_dynamic_data_(nullptr),
is_loaned_(false),
parent_data_(nullptr)
{
if (!serialization_support_) {
throw std::runtime_error("dynamic type could not bind serialization support!");
}
rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder =
dynamic_type_builder->get_rosidl_dynamic_type_builder();
if (!rosidl_dynamic_type_builder) {
throw std::runtime_error("dynamic type builder cannot be nullptr!");
}
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_create_from_dynamic_type_builder(
rosidl_dynamic_type_builder, &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_data) {
throw std::runtime_error("could not create new dynamic data object from dynamic type builder");
}
rosidl_dynamic_data_.reset(
rosidl_dynamic_data,
// Custom deleter
[](rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data)->void {
rosidl_dynamic_typesupport_dynamic_data_destroy(rosidl_dynamic_data);
});
}
DynamicMessage::DynamicMessage(const DynamicMessageType::SharedPtr dynamic_type)
: serialization_support_(dynamic_type->get_shared_dynamic_serialization_support()),
rosidl_dynamic_data_(nullptr),
is_loaned_(false),
parent_data_(nullptr)
{
if (!serialization_support_) {
throw std::runtime_error("dynamic type could not bind serialization support!");
}
rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type =
dynamic_type->get_rosidl_dynamic_type();
if (!rosidl_dynamic_type) {
throw std::runtime_error("dynamic type cannot be nullptr!");
}
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_create_from_dynamic_type(
rosidl_dynamic_type, &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_data) {
throw std::runtime_error(
std::string("could not create new dynamic data object from dynamic type") +
rcl_get_error_string().str);
}
rosidl_dynamic_data_.reset(
rosidl_dynamic_data,
// Custom deleter
[](rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data)->void {
rosidl_dynamic_typesupport_dynamic_data_destroy(rosidl_dynamic_data);
});
}
DynamicMessage::DynamicMessage(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data)
: serialization_support_(serialization_support),
rosidl_dynamic_data_(nullptr),
is_loaned_(false),
parent_data_(nullptr)
{
if (!rosidl_dynamic_data) {
throw std::runtime_error("rosidl dynamic data cannot be nullptr!");
}
if (serialization_support) {
if (!match_serialization_support_(*serialization_support, *rosidl_dynamic_data)) {
throw std::runtime_error(
"serialization support library identifier does not match dynamic data's!");
}
}
rosidl_dynamic_data_.reset(
rosidl_dynamic_data,
// Custom deleter
[](rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data)->void {
rosidl_dynamic_typesupport_dynamic_data_destroy(rosidl_dynamic_data);
});
}
DynamicMessage::DynamicMessage(
DynamicSerializationSupport::SharedPtr serialization_support,
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_data_t> rosidl_dynamic_data)
: serialization_support_(serialization_support),
rosidl_dynamic_data_(rosidl_dynamic_data),
is_loaned_(false),
parent_data_(nullptr)
{
if (!rosidl_dynamic_data) {
throw std::runtime_error("rosidl dynamic data cannot be nullptr!");
}
if (serialization_support) {
if (!match_serialization_support_(*serialization_support, *rosidl_dynamic_data)) {
throw std::runtime_error(
"serialization support library identifier does not match dynamic data's!");
}
}
}
DynamicMessage::DynamicMessage(
DynamicMessage::SharedPtr parent_data,
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_loaned_data)
: serialization_support_(parent_data->get_shared_dynamic_serialization_support()),
rosidl_dynamic_data_(nullptr),
is_loaned_(true),
parent_data_(nullptr)
{
if (!parent_data) {
throw std::runtime_error("parent dynamic data cannot be nullptr!");
}
if (!rosidl_loaned_data) {
throw std::runtime_error("loaned rosidl dynamic data cannot be nullptr!");
}
if (serialization_support_) {
if (!match_serialization_support_(*serialization_support_, *rosidl_loaned_data)) {
throw std::runtime_error(
"serialization support library identifier does not match loaned dynamic data's!");
}
}
rosidl_dynamic_data_.reset(
rosidl_loaned_data,
// Custom no-op deleter
[](rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data)->void {
// Data fini and destruction is deferred to return_loaned_value()
(void) rosidl_dynamic_data;
});
parent_data_ = parent_data;
}
DynamicMessage::DynamicMessage(const DynamicMessage & other)
: enable_shared_from_this(),
serialization_support_(nullptr),
rosidl_dynamic_data_(nullptr),
is_loaned_(false),
parent_data_(nullptr)
{
DynamicMessage out = other.clone();
// We don't copy is_loaned_ or parent_data_ because it's a fresh copy now
std::swap(serialization_support_, out.serialization_support_);
std::swap(rosidl_dynamic_data_, out.rosidl_dynamic_data_);
}
DynamicMessage::DynamicMessage(DynamicMessage && other) noexcept
: serialization_support_(std::exchange(other.serialization_support_, nullptr)),
rosidl_dynamic_data_(std::exchange(other.rosidl_dynamic_data_, nullptr)),
is_loaned_(other.is_loaned_),
parent_data_(std::exchange(other.parent_data_, nullptr))
{}
DynamicMessage &
DynamicMessage::operator=(const DynamicMessage & other)
{
return *this = DynamicMessage(other);
}
DynamicMessage &
DynamicMessage::operator=(DynamicMessage && other) noexcept
{
std::swap(serialization_support_, other.serialization_support_);
std::swap(rosidl_dynamic_data_, other.rosidl_dynamic_data_);
is_loaned_ = other.is_loaned_;
std::swap(parent_data_, other.parent_data_);
return *this;
}
DynamicMessage::~DynamicMessage()
{
if (is_loaned_) {
if (!parent_data_) {
RCUTILS_LOG_ERROR("dynamic data is loaned, but parent is missing!!");
} else {
rosidl_dynamic_typesupport_dynamic_data_return_loaned_value(
parent_data_->get_rosidl_dynamic_data(), get_rosidl_dynamic_data());
}
}
}
bool
DynamicMessage::match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_data_t & rosidl_dynamic_type_data)
{
bool out = true;
if (serialization_support.get_library_identifier() != std::string(
rosidl_dynamic_type_data.serialization_support->library_identifier))
{
RCUTILS_LOG_ERROR("serialization support library identifier does not match dynamic data's");
out = false;
}
// TODO(methylDragon): Can I do this?? Is it portable?
if (serialization_support.get_rosidl_serialization_support() !=
rosidl_dynamic_type_data.serialization_support)
{
RCUTILS_LOG_ERROR("serialization support pointer does not match dynamic data's");
out = false;
}
return out;
}
// GETTERS =======================================================================================
const std::string
DynamicMessage::get_library_identifier() const
{
return std::string(rosidl_dynamic_data_->serialization_support->library_identifier);
}
const std::string
DynamicMessage::get_name() const
{
size_t buf_length;
const char * buf;
if (
rosidl_dynamic_typesupport_dynamic_data_get_name(
get_rosidl_dynamic_data(), &buf,
&buf_length) !=
RCUTILS_RET_OK)
{
throw std::runtime_error(
std::string("could not get name for dynamic data") + rcl_get_error_string().str);
}
return std::string(buf, buf_length);
}
rosidl_dynamic_typesupport_dynamic_data_t *
DynamicMessage::get_rosidl_dynamic_data()
{
return rosidl_dynamic_data_.get();
}
const rosidl_dynamic_typesupport_dynamic_data_t *
DynamicMessage::get_rosidl_dynamic_data() const
{
return rosidl_dynamic_data_.get();
}
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_data_t>
DynamicMessage::get_shared_rosidl_dynamic_data()
{
return std::shared_ptr<rosidl_dynamic_typesupport_dynamic_data_t>(
shared_from_this(), rosidl_dynamic_data_.get());
}
std::shared_ptr<const rosidl_dynamic_typesupport_dynamic_data_t>
DynamicMessage::get_shared_rosidl_dynamic_data() const
{
return std::shared_ptr<rosidl_dynamic_typesupport_dynamic_data_t>(
shared_from_this(), rosidl_dynamic_data_.get());
}
DynamicSerializationSupport::SharedPtr
DynamicMessage::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
DynamicSerializationSupport::ConstSharedPtr
DynamicMessage::get_shared_dynamic_serialization_support() const
{
return serialization_support_;
}
size_t
DynamicMessage::get_item_count() const
{
size_t item_count;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_item_count(
get_rosidl_dynamic_data(), &item_count);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not get item count of dynamic data");
}
return item_count;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::get_member_id(size_t index) const
{
rosidl_dynamic_typesupport_member_id_t member_id;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_member_id_at_index(
get_rosidl_dynamic_data(), index, &member_id);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not member id of dynamic data element by index");
}
return member_id;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::get_member_id(const std::string & name) const
{
rosidl_dynamic_typesupport_member_id_t member_id;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_member_id_by_name(
get_rosidl_dynamic_data(), name.c_str(), name.size(), &member_id);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not member id of dynamic data element by name");
}
return member_id;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::get_array_index(size_t index) const
{
rosidl_dynamic_typesupport_member_id_t array_index;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_get_array_index(
get_rosidl_dynamic_data(), index, &array_index);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not array index of dynamic data element by index");
}
return array_index;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::get_array_index(const std::string & name) const
{
return get_array_index(get_member_id(name));
}
// METHODS =======================================================================================
DynamicMessage
DynamicMessage::clone() const
{
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_clone(
get_rosidl_dynamic_data(), &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_data) {
throw std::runtime_error(
std::string("could not clone dynamic data: ") + rcl_get_error_string().str);
}
return DynamicMessage(serialization_support_, rosidl_dynamic_data);
}
DynamicMessage::SharedPtr
DynamicMessage::clone_shared() const
{
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_clone(
get_rosidl_dynamic_data(), &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_data) {
throw std::runtime_error(
std::string("could not clone dynamic data: ") + rcl_get_error_string().str);
}
return DynamicMessage::make_shared(serialization_support_, rosidl_dynamic_data);
}
DynamicMessage
DynamicMessage::init_from_type(DynamicMessageType & type) const
{
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_create_from_dynamic_type(
type.get_rosidl_dynamic_type(), &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_data) {
throw std::runtime_error("could not create new dynamic data object from dynamic type");
}
return DynamicMessage(serialization_support_, rosidl_dynamic_data);
}
DynamicMessage::SharedPtr
DynamicMessage::init_from_type_shared(DynamicMessageType & type) const
{
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_create_from_dynamic_type(
type.get_rosidl_dynamic_type(), &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_data) {
throw std::runtime_error("could not create new dynamic data object from dynamic type");
}
return DynamicMessage::make_shared(serialization_support_, rosidl_dynamic_data);
}
bool
DynamicMessage::equals(const DynamicMessage & other) const
{
if (get_library_identifier() != other.get_library_identifier()) {
throw std::runtime_error("library identifiers don't match");
}
bool equals;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_equals(
get_rosidl_dynamic_data(), other.get_rosidl_dynamic_data(), &equals);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error("could not equate dynamic messages");
}
return equals;
}
DynamicMessage::SharedPtr
DynamicMessage::loan_value(rosidl_dynamic_typesupport_member_id_t id)
{
rosidl_dynamic_typesupport_dynamic_data_t * rosidl_dynamic_data = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_data_loan_value(
get_rosidl_dynamic_data(), id, &rosidl_dynamic_data);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_data) {
throw std::runtime_error(
std::string("could not loan dynamic data: ") + rcl_get_error_string().str);
}
return DynamicMessage::make_shared(shared_from_this(), rosidl_dynamic_data);
}
DynamicMessage::SharedPtr
DynamicMessage::loan_value(const std::string & name)
{
return loan_value(get_member_id(name));
}
void
DynamicMessage::clear_all_values()
{
rosidl_dynamic_typesupport_dynamic_data_clear_all_values(get_rosidl_dynamic_data());
}
void
DynamicMessage::clear_nonkey_values()
{
rosidl_dynamic_typesupport_dynamic_data_clear_nonkey_values(get_rosidl_dynamic_data());
}
void
DynamicMessage::clear_value(rosidl_dynamic_typesupport_member_id_t id)
{
rosidl_dynamic_typesupport_dynamic_data_clear_value(get_rosidl_dynamic_data(), id);
}
void
DynamicMessage::clear_value(const std::string & name)
{
clear_value(get_member_id(name));
}
void
DynamicMessage::clear_sequence()
{
rosidl_dynamic_typesupport_dynamic_data_clear_sequence_data(get_rosidl_dynamic_data());
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_sequence_data()
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_sequence_data(get_rosidl_dynamic_data(), &out);
return out;
}
void
DynamicMessage::remove_sequence_data(rosidl_dynamic_typesupport_member_id_t index)
{
rosidl_dynamic_typesupport_dynamic_data_remove_sequence_data(
get_rosidl_dynamic_data(), index);
}
bool
DynamicMessage::serialize(rcl_serialized_message_t * buffer)
{
bool success;
rcutils_ret_t ret =
rosidl_dynamic_typesupport_dynamic_data_serialize(get_rosidl_dynamic_data(), buffer, &success);
if (ret != RCUTILS_RET_OK || !success) {
throw std::runtime_error(
std::string("could serialize loan dynamic data: ") + rcl_get_error_string().str);
}
return success;
}
bool
DynamicMessage::deserialize(rcl_serialized_message_t * buffer)
{
bool success;
rcutils_ret_t ret =
rosidl_dynamic_typesupport_dynamic_data_deserialize(
get_rosidl_dynamic_data(), buffer,
&success);
if (ret != RCUTILS_RET_OK || !success) {
throw std::runtime_error(
std::string("could deserialize loan dynamic data: ") + rcl_get_error_string().str);
}
return success;
}
// MEMBER ACCESS ===================================================================================
// Defined in "detail/dynamic_message_impl.hpp"
// FIXED STRING MEMBER ACCESS ======================================================================
const std::string
DynamicMessage::get_fixed_string_value(
rosidl_dynamic_typesupport_member_id_t id, size_t string_length)
{
size_t buf_length;
char * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_fixed_string_value(
get_rosidl_dynamic_data(), id, &buf, &buf_length, string_length);
auto out = std::string(buf, buf_length);
delete buf;
return out;
}
const std::string
DynamicMessage::get_fixed_string_value(const std::string & name, size_t string_length)
{
return get_fixed_string_value(get_member_id(name), string_length);
}
const std::u16string
DynamicMessage::get_fixed_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, size_t wstring_length)
{
size_t buf_length;
char16_t * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_fixed_wstring_value(
get_rosidl_dynamic_data(), id, &buf, &buf_length, wstring_length);
auto out = std::u16string(buf, buf_length);
delete buf;
return out;
}
const std::u16string
DynamicMessage::get_fixed_wstring_value(const std::string & name, size_t wstring_length)
{
return get_fixed_wstring_value(get_member_id(name), wstring_length);
}
void
DynamicMessage::set_fixed_string_value(
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_length)
{
rosidl_dynamic_typesupport_dynamic_data_set_fixed_string_value(
get_rosidl_dynamic_data(), id, value.c_str(), value.size(), string_length);
}
void
DynamicMessage::set_fixed_string_value(
const std::string & name, const std::string value, size_t string_length)
{
set_fixed_string_value(get_member_id(name), value, string_length);
}
void
DynamicMessage::set_fixed_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_length)
{
rosidl_dynamic_typesupport_dynamic_data_set_fixed_wstring_value(
get_rosidl_dynamic_data(), id, value.c_str(), value.size(), wstring_length);
}
void
DynamicMessage::set_fixed_wstring_value(
const std::string & name, const std::u16string value, size_t wstring_length)
{
set_fixed_wstring_value(get_member_id(name), value, wstring_length);
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_fixed_string_value(const std::string value, size_t string_length)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_fixed_string_value(
get_rosidl_dynamic_data(), value.c_str(), value.size(), string_length, &out);
return out;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_fixed_wstring_value(const std::u16string value, size_t wstring_length)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_fixed_wstring_value(
get_rosidl_dynamic_data(), value.c_str(), value.size(), wstring_length, &out);
return out;
}
// BOUNDED STRING MEMBER ACCESS ====================================================================
const std::string
DynamicMessage::get_bounded_string_value(
rosidl_dynamic_typesupport_member_id_t id, size_t string_bound)
{
size_t buf_length;
char * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_bounded_string_value(
get_rosidl_dynamic_data(), id, &buf, &buf_length, string_bound);
auto out = std::string(buf, buf_length);
delete buf;
return out;
}
const std::string
DynamicMessage::get_bounded_string_value(const std::string & name, size_t string_bound)
{
return get_bounded_string_value(get_member_id(name), string_bound);
}
const std::u16string
DynamicMessage::get_bounded_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, size_t wstring_bound)
{
size_t buf_length;
char16_t * buf = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_bounded_wstring_value(
get_rosidl_dynamic_data(), id, &buf, &buf_length, wstring_bound);
auto out = std::u16string(buf, buf_length);
delete buf;
return out;
}
const std::u16string
DynamicMessage::get_bounded_wstring_value(const std::string & name, size_t wstring_bound)
{
return get_bounded_wstring_value(get_member_id(name), wstring_bound);
}
void
DynamicMessage::set_bounded_string_value(
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_bound)
{
rosidl_dynamic_typesupport_dynamic_data_set_bounded_string_value(
get_rosidl_dynamic_data(), id, value.c_str(), value.size(), string_bound);
}
void
DynamicMessage::set_bounded_string_value(
const std::string & name, const std::string value, size_t string_bound)
{
set_bounded_string_value(get_member_id(name), value, string_bound);
}
void
DynamicMessage::set_bounded_wstring_value(
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_bound)
{
rosidl_dynamic_typesupport_dynamic_data_set_bounded_wstring_value(
get_rosidl_dynamic_data(), id, value.c_str(), value.size(), wstring_bound);
}
void
DynamicMessage::set_bounded_wstring_value(
const std::string & name, const std::u16string value, size_t wstring_bound)
{
set_bounded_wstring_value(get_member_id(name), value, wstring_bound);
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_bounded_string_value(const std::string value, size_t string_bound)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_bounded_string_value(
get_rosidl_dynamic_data(), value.c_str(), value.size(), string_bound, &out);
return out;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_bounded_wstring_value(const std::u16string value, size_t wstring_bound)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_bounded_wstring_value(
get_rosidl_dynamic_data(), value.c_str(), value.size(), wstring_bound, &out);
return out;
}
// NESTED MEMBER ACCESS ============================================================================
DynamicMessage
DynamicMessage::get_complex_value(rosidl_dynamic_typesupport_member_id_t id)
{
rosidl_dynamic_typesupport_dynamic_data_t * out_ptr = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_complex_value(
get_rosidl_dynamic_data(), id, &out_ptr);
return DynamicMessage(get_shared_dynamic_serialization_support(), out_ptr);
}
DynamicMessage
DynamicMessage::get_complex_value(const std::string & name)
{
return get_complex_value(get_member_id(name));
}
DynamicMessage::SharedPtr
DynamicMessage::get_complex_value_shared(rosidl_dynamic_typesupport_member_id_t id)
{
rosidl_dynamic_typesupport_dynamic_data_t * out_ptr = nullptr;
rosidl_dynamic_typesupport_dynamic_data_get_complex_value(
get_rosidl_dynamic_data(), id, &out_ptr);
return DynamicMessage::make_shared(get_shared_dynamic_serialization_support(), out_ptr);
}
DynamicMessage::SharedPtr
DynamicMessage::get_complex_value_shared(const std::string & name)
{
return get_complex_value_shared(get_member_id(name));
}
void
DynamicMessage::set_complex_value(
rosidl_dynamic_typesupport_member_id_t id, DynamicMessage & value)
{
rosidl_dynamic_typesupport_dynamic_data_set_complex_value(
get_rosidl_dynamic_data(), id, value.get_rosidl_dynamic_data());
}
void
DynamicMessage::set_complex_value(const std::string & name, DynamicMessage & value)
{
set_complex_value(get_member_id(name), value);
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_complex_value_copy(const DynamicMessage & value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_complex_value_copy(
get_rosidl_dynamic_data(), value.get_rosidl_dynamic_data(), &out);
return out;
}
rosidl_dynamic_typesupport_member_id_t
DynamicMessage::insert_complex_value(DynamicMessage & value)
{
rosidl_dynamic_typesupport_member_id_t out;
rosidl_dynamic_typesupport_dynamic_data_insert_complex_value(
get_rosidl_dynamic_data(), value.get_rosidl_dynamic_data(), &out);
return out;
}

View File

@@ -0,0 +1,338 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rcutils/logging_macros.h"
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/exceptions.hpp"
using rclcpp::dynamic_typesupport::DynamicMessage;
using rclcpp::dynamic_typesupport::DynamicMessageType;
using rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder;
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
// CONSTRUCTION ====================================================================================
DynamicMessageType::DynamicMessageType(DynamicMessageTypeBuilder::SharedPtr dynamic_type_builder)
: serialization_support_(dynamic_type_builder->get_shared_dynamic_serialization_support()),
rosidl_dynamic_type_(nullptr)
{
if (!serialization_support_) {
throw std::runtime_error("dynamic type could not bind serialization support!");
}
rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder =
dynamic_type_builder->get_rosidl_dynamic_type_builder();
if (!rosidl_dynamic_type_builder) {
throw std::runtime_error("dynamic type builder cannot be nullptr!");
}
rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_create_from_dynamic_type_builder(
rosidl_dynamic_type_builder, &rosidl_dynamic_type);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_type) {
throw std::runtime_error("could not create new dynamic type object");
}
rosidl_dynamic_type_.reset(
rosidl_dynamic_type,
// Custom deleter
[](rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type)->void {
rosidl_dynamic_typesupport_dynamic_type_destroy(rosidl_dynamic_type);
});
}
DynamicMessageType::DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type)
: serialization_support_(serialization_support), rosidl_dynamic_type_(nullptr)
{
if (!rosidl_dynamic_type) {
throw std::runtime_error("rosidl dynamic type cannot be nullptr!");
}
if (serialization_support) {
if (!match_serialization_support_(*serialization_support, *rosidl_dynamic_type)) {
throw std::runtime_error(
"serialization support library identifier does not match dynamic type's!");
}
}
rosidl_dynamic_type_.reset(
rosidl_dynamic_type,
// Custom deleter
[](rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type)->void {
rosidl_dynamic_typesupport_dynamic_type_destroy(rosidl_dynamic_type);
});
}
DynamicMessageType::DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_t> rosidl_dynamic_type)
: serialization_support_(serialization_support), rosidl_dynamic_type_(rosidl_dynamic_type)
{
if (!rosidl_dynamic_type) {
throw std::runtime_error("rosidl dynamic type cannot be nullptr!");
}
if (serialization_support) {
if (!match_serialization_support_(*serialization_support, *rosidl_dynamic_type)) {
throw std::runtime_error(
"serialization support library identifier does not match dynamic type's!");
}
}
}
DynamicMessageType::DynamicMessageType(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description)
: serialization_support_(serialization_support), rosidl_dynamic_type_(nullptr)
{
init_from_description(description, serialization_support);
}
DynamicMessageType::DynamicMessageType(const DynamicMessageType & other)
: enable_shared_from_this(), serialization_support_(nullptr), rosidl_dynamic_type_(nullptr)
{
DynamicMessageType out = other.clone();
std::swap(serialization_support_, out.serialization_support_);
std::swap(rosidl_dynamic_type_, out.rosidl_dynamic_type_);
}
DynamicMessageType::DynamicMessageType(DynamicMessageType && other) noexcept
: serialization_support_(std::exchange(other.serialization_support_, nullptr)),
rosidl_dynamic_type_(std::exchange(other.rosidl_dynamic_type_, nullptr)) {}
DynamicMessageType &
DynamicMessageType::operator=(const DynamicMessageType & other)
{
return *this = DynamicMessageType(other);
}
DynamicMessageType &
DynamicMessageType::operator=(DynamicMessageType && other) noexcept
{
std::swap(serialization_support_, other.serialization_support_);
std::swap(rosidl_dynamic_type_, other.rosidl_dynamic_type_);
return *this;
}
DynamicMessageType::~DynamicMessageType() {}
void
DynamicMessageType::init_from_description(
const rosidl_runtime_c__type_description__TypeDescription & description,
DynamicSerializationSupport::SharedPtr serialization_support)
{
if (serialization_support) {
// Swap serialization support if serialization support is given
serialization_support_ = serialization_support;
}
rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_create_from_description(
serialization_support_->get_rosidl_serialization_support(), &description, &rosidl_dynamic_type);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_type) {
throw std::runtime_error("could not create new dynamic type object");
}
rosidl_dynamic_type_.reset(
rosidl_dynamic_type,
// Custom deleter
[](rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type)->void {
rosidl_dynamic_typesupport_dynamic_type_destroy(rosidl_dynamic_type);
});
}
bool
DynamicMessageType::match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_type_t & rosidl_dynamic_type)
{
bool out = true;
if (serialization_support.get_library_identifier() != std::string(
rosidl_dynamic_type.serialization_support->library_identifier))
{
RCUTILS_LOG_ERROR(
"serialization support library identifier does not match dynamic type's");
out = false;
}
// TODO(methylDragon): Can I do this?? Is it portable?
if (serialization_support.get_rosidl_serialization_support() !=
rosidl_dynamic_type.serialization_support)
{
RCUTILS_LOG_ERROR(
"serialization support pointer does not match dynamic type's");
out = false;
}
return out;
}
// GETTERS =========================================================================================
const std::string
DynamicMessageType::get_library_identifier() const
{
return std::string(rosidl_dynamic_type_->serialization_support->library_identifier);
}
const std::string
DynamicMessageType::get_name() const
{
size_t buf_length;
const char * buf;
rosidl_dynamic_typesupport_dynamic_type_get_name(get_rosidl_dynamic_type(), &buf, &buf_length);
return std::string(buf, buf_length);
}
size_t
DynamicMessageType::get_member_count() const
{
size_t out;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_get_member_count(
rosidl_dynamic_type_.get(), &out);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not get member count: ") + rcl_get_error_string().str);
}
return out;
}
rosidl_dynamic_typesupport_dynamic_type_t *
DynamicMessageType::get_rosidl_dynamic_type()
{
return rosidl_dynamic_type_.get();
}
const rosidl_dynamic_typesupport_dynamic_type_t *
DynamicMessageType::get_rosidl_dynamic_type() const
{
return rosidl_dynamic_type_.get();
}
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_t>
DynamicMessageType::get_shared_rosidl_dynamic_type()
{
return std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_t>(
shared_from_this(), rosidl_dynamic_type_.get());
}
std::shared_ptr<const rosidl_dynamic_typesupport_dynamic_type_t>
DynamicMessageType::get_shared_rosidl_dynamic_type() const
{
return std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_t>(
shared_from_this(), rosidl_dynamic_type_.get());
}
DynamicSerializationSupport::SharedPtr
DynamicMessageType::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
DynamicSerializationSupport::ConstSharedPtr
DynamicMessageType::get_shared_dynamic_serialization_support() const
{
return serialization_support_;
}
// METHODS =========================================================================================
DynamicMessageType
DynamicMessageType::clone() const
{
rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_clone(
get_rosidl_dynamic_type(), &rosidl_dynamic_type);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_type) {
throw std::runtime_error(
std::string("could not clone dynamic type: ") + rcl_get_error_string().str);
}
return DynamicMessageType(serialization_support_, rosidl_dynamic_type);
}
DynamicMessageType::SharedPtr
DynamicMessageType::clone_shared() const
{
rosidl_dynamic_typesupport_dynamic_type_t * rosidl_dynamic_type = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_clone(
get_rosidl_dynamic_type(), &rosidl_dynamic_type);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_type) {
throw std::runtime_error(
std::string("could not clone dynamic type: ") + rcl_get_error_string().str);
}
return DynamicMessageType::make_shared(serialization_support_, rosidl_dynamic_type);
}
bool
DynamicMessageType::equals(const DynamicMessageType & other) const
{
if (get_library_identifier() != other.get_library_identifier()) {
throw std::runtime_error("library identifiers don't match");
}
bool out;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_equals(
get_rosidl_dynamic_type(), other.get_rosidl_dynamic_type(), &out);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not equate dynamic message types: ") + rcl_get_error_string().str);
}
return out;
}
DynamicMessage
DynamicMessageType::build_dynamic_message()
{
return DynamicMessage(shared_from_this());
}
DynamicMessage::SharedPtr
DynamicMessageType::build_dynamic_message_shared()
{
return DynamicMessage::make_shared(shared_from_this());
}

View File

@@ -0,0 +1,675 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <memory>
#include <string>
#include "rcutils/logging_macros.h"
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/exceptions.hpp"
using rclcpp::dynamic_typesupport::DynamicMessage;
using rclcpp::dynamic_typesupport::DynamicMessageType;
using rclcpp::dynamic_typesupport::DynamicMessageTypeBuilder;
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
// Template specialization implementations
#include "rclcpp/dynamic_typesupport/detail/dynamic_message_type_builder_impl.hpp"
#endif
// CONSTRUCTION ====================================================================================
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support, const std::string & name)
: serialization_support_(serialization_support), rosidl_dynamic_type_builder_(nullptr)
{
init_from_serialization_support_(serialization_support, name);
if (!rosidl_dynamic_type_builder_) {
throw std::runtime_error("could not create new dynamic type builder object");
}
}
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder)
: serialization_support_(serialization_support), rosidl_dynamic_type_builder_(nullptr)
{
if (!serialization_support) {
throw std::runtime_error("serialization support cannot be nullptr!");
}
if (!rosidl_dynamic_type_builder) {
throw std::runtime_error("rosidl dynamic type builder cannot be nullptr!");
}
if (!match_serialization_support_(*serialization_support, *rosidl_dynamic_type_builder)) {
throw std::runtime_error(
"serialization support library does not match dynamic type builder's!");
}
rosidl_dynamic_type_builder_.reset(
rosidl_dynamic_type_builder,
// Custom deleter
[](rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder)->void {
rosidl_dynamic_typesupport_dynamic_type_builder_destroy(rosidl_dynamic_type_builder);
});
}
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_builder_t> rosidl_dynamic_type_builder)
: serialization_support_(serialization_support),
rosidl_dynamic_type_builder_(rosidl_dynamic_type_builder)
{
if (!serialization_support) {
throw std::runtime_error("serialization support cannot be nullptr!");
}
if (!rosidl_dynamic_type_builder) {
throw std::runtime_error("rosidl dynamic type builder cannot be nullptr!");
}
if (!match_serialization_support_(*serialization_support, *rosidl_dynamic_type_builder.get())) {
throw std::runtime_error(
"serialization support library does not match dynamic type builder's!");
}
}
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description)
: serialization_support_(serialization_support),
rosidl_dynamic_type_builder_(nullptr)
{
if (!serialization_support) {
throw std::runtime_error("serialization support cannot be nullptr!");
}
init_from_description(description, serialization_support);
}
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(const DynamicMessageTypeBuilder & other)
: enable_shared_from_this(), serialization_support_(nullptr), rosidl_dynamic_type_builder_(nullptr)
{
DynamicMessageTypeBuilder out = other.clone();
std::swap(serialization_support_, out.serialization_support_);
std::swap(rosidl_dynamic_type_builder_, out.rosidl_dynamic_type_builder_);
}
DynamicMessageTypeBuilder::DynamicMessageTypeBuilder(DynamicMessageTypeBuilder && other) noexcept
: serialization_support_(std::exchange(other.serialization_support_, nullptr)),
rosidl_dynamic_type_builder_(std::exchange(other.rosidl_dynamic_type_builder_, nullptr)) {}
DynamicMessageTypeBuilder &
DynamicMessageTypeBuilder::operator=(const DynamicMessageTypeBuilder & other)
{
return *this = DynamicMessageTypeBuilder(other);
}
DynamicMessageTypeBuilder &
DynamicMessageTypeBuilder::operator=(DynamicMessageTypeBuilder && other) noexcept
{
std::swap(serialization_support_, other.serialization_support_);
std::swap(rosidl_dynamic_type_builder_, other.rosidl_dynamic_type_builder_);
return *this;
}
DynamicMessageTypeBuilder::~DynamicMessageTypeBuilder() {}
void
DynamicMessageTypeBuilder::init_from_description(
const rosidl_runtime_c__type_description__TypeDescription & description,
DynamicSerializationSupport::SharedPtr serialization_support)
{
if (serialization_support) {
// Swap serialization support if serialization support is given
serialization_support_ = serialization_support;
}
rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_create_from_description(
serialization_support_->get_rosidl_serialization_support(), &description,
&rosidl_dynamic_type_builder);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_type_builder) {
throw std::runtime_error("could not create new dynamic type builder object");
}
rosidl_dynamic_type_builder_.reset(
rosidl_dynamic_type_builder,
// Custom deleter
[](rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder)->void {
rosidl_dynamic_typesupport_dynamic_type_builder_destroy(rosidl_dynamic_type_builder);
});
}
void
DynamicMessageTypeBuilder::init_from_serialization_support_(
DynamicSerializationSupport::SharedPtr serialization_support,
const std::string & name)
{
if (!serialization_support) {
throw std::runtime_error("serialization support cannot be nullptr!");
}
if (!serialization_support->get_rosidl_serialization_support()) {
throw std::runtime_error("serialization support raw pointer cannot be nullptr!");
}
rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_create(
serialization_support->get_rosidl_serialization_support(),
name.c_str(), name.size(),
&rosidl_dynamic_type_builder);
if (ret != RCUTILS_RET_OK) {
throw std::runtime_error(
std::string("could not init dynamic type builder: ") + rcl_get_error_string().str);
}
if (!rosidl_dynamic_type_builder) {
throw std::runtime_error("could not init dynamic type builder object");
}
rosidl_dynamic_type_builder_.reset(
rosidl_dynamic_type_builder,
// Custom deleter
[](rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder)->void {
rosidl_dynamic_typesupport_dynamic_type_builder_destroy(rosidl_dynamic_type_builder);
});
}
bool
DynamicMessageTypeBuilder::match_serialization_support_(
const DynamicSerializationSupport & serialization_support,
const rosidl_dynamic_typesupport_dynamic_type_builder_t & rosidl_dynamic_type_builder)
{
bool out = true;
if (serialization_support.get_library_identifier() != std::string(
rosidl_dynamic_type_builder.serialization_support->library_identifier))
{
RCUTILS_LOG_ERROR(
"serialization support library identifier does not match dynamic type builder's");
out = false;
}
// TODO(methylDragon): Can I do this?? Is it portable?
if (serialization_support.get_rosidl_serialization_support() !=
rosidl_dynamic_type_builder.serialization_support)
{
RCUTILS_LOG_ERROR(
"serialization support pointer does not match dynamic type builder's");
out = false;
}
return out;
}
// GETTERS =======================================================================================
const std::string
DynamicMessageTypeBuilder::get_library_identifier() const
{
return std::string(rosidl_dynamic_type_builder_->serialization_support->library_identifier);
}
const std::string
DynamicMessageTypeBuilder::get_name() const
{
size_t buf_length;
const char * buf;
rosidl_dynamic_typesupport_dynamic_type_builder_get_name(
get_rosidl_dynamic_type_builder(), &buf, &buf_length);
return std::string(buf, buf_length);
}
rosidl_dynamic_typesupport_dynamic_type_builder_t *
DynamicMessageTypeBuilder::get_rosidl_dynamic_type_builder()
{
return rosidl_dynamic_type_builder_.get();
}
const rosidl_dynamic_typesupport_dynamic_type_builder_t *
DynamicMessageTypeBuilder::get_rosidl_dynamic_type_builder() const
{
return rosidl_dynamic_type_builder_.get();
}
std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_builder_t>
DynamicMessageTypeBuilder::get_shared_rosidl_dynamic_type_builder()
{
return std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_builder_t>(
shared_from_this(), rosidl_dynamic_type_builder_.get());
}
std::shared_ptr<const rosidl_dynamic_typesupport_dynamic_type_builder_t>
DynamicMessageTypeBuilder::get_shared_rosidl_dynamic_type_builder() const
{
return std::shared_ptr<rosidl_dynamic_typesupport_dynamic_type_builder_t>(
shared_from_this(), rosidl_dynamic_type_builder_.get());
}
DynamicSerializationSupport::SharedPtr
DynamicMessageTypeBuilder::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
DynamicSerializationSupport::ConstSharedPtr
DynamicMessageTypeBuilder::get_shared_dynamic_serialization_support() const
{
return serialization_support_;
}
// METHODS =======================================================================================
void
DynamicMessageTypeBuilder::set_name(const std::string & name)
{
rosidl_dynamic_typesupport_dynamic_type_builder_set_name(
get_rosidl_dynamic_type_builder(), name.c_str(), name.size());
}
DynamicMessageTypeBuilder
DynamicMessageTypeBuilder::clone() const
{
rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_clone(
get_rosidl_dynamic_type_builder(), &rosidl_dynamic_type_builder);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_type_builder) {
throw std::runtime_error(
std::string("could not clone dynamic type builder: ") + rcl_get_error_string().str);
}
return DynamicMessageTypeBuilder(serialization_support_, rosidl_dynamic_type_builder);
}
DynamicMessageTypeBuilder::SharedPtr
DynamicMessageTypeBuilder::clone_shared() const
{
rosidl_dynamic_typesupport_dynamic_type_builder_t * rosidl_dynamic_type_builder = nullptr;
rcutils_ret_t ret = rosidl_dynamic_typesupport_dynamic_type_builder_clone(
get_rosidl_dynamic_type_builder(), &rosidl_dynamic_type_builder);
if (ret != RCUTILS_RET_OK || !rosidl_dynamic_type_builder) {
throw std::runtime_error(
std::string("could not clone dynamic type builder: ") + rcl_get_error_string().str);
}
return DynamicMessageTypeBuilder::make_shared(
serialization_support_, rosidl_dynamic_type_builder);
}
void
DynamicMessageTypeBuilder::clear()
{
if (!serialization_support_) {
throw std::runtime_error(
"cannot call clear() on a dynamic type builder with uninitialized serialization support"
);
}
const std::string & name = get_name();
init_from_serialization_support_(serialization_support_, name);
if (!rosidl_dynamic_type_builder_) {
throw std::runtime_error("could not create new dynamic type builder object");
}
}
DynamicMessage
DynamicMessageTypeBuilder::build_dynamic_message()
{
return DynamicMessage(shared_from_this());
}
DynamicMessage::SharedPtr
DynamicMessageTypeBuilder::build_dynamic_message_shared()
{
return DynamicMessage::make_shared(shared_from_this());
}
DynamicMessageType
DynamicMessageTypeBuilder::build_dynamic_message_type()
{
return DynamicMessageType(shared_from_this());
}
DynamicMessageType::SharedPtr
DynamicMessageTypeBuilder::build_dynamic_message_type_shared()
{
return DynamicMessageType::make_shared(shared_from_this());
}
// ADD MEMBERS =====================================================================================
// Defined in "detail/dynamic_message_type_builder_impl.hpp"
// ADD FIXED STRING MEMBERS ========================================================================
void
DynamicMessageTypeBuilder::add_fixed_string_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_length);
}
void
DynamicMessageTypeBuilder::add_fixed_wstring_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_length);
}
void
DynamicMessageTypeBuilder::add_fixed_string_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_length, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_array_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_length, array_length);
}
void
DynamicMessageTypeBuilder::add_fixed_wstring_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_length, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_array_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_length, array_length);
}
void
DynamicMessageTypeBuilder::add_fixed_string_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_unbounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_length);
}
void
DynamicMessageTypeBuilder::add_fixed_wstring_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_unbounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_length);
}
void
DynamicMessageTypeBuilder::add_fixed_string_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_length, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_string_bounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_length, sequence_bound);
}
void
DynamicMessageTypeBuilder::add_fixed_wstring_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_length, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_fixed_wstring_bounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_length, sequence_bound);
}
// ADD BOUNDED STRING MEMBERS ======================================================================
void
DynamicMessageTypeBuilder::add_bounded_string_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_wstring_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_string_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_bound, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_array_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_bound, array_length);
}
void
DynamicMessageTypeBuilder::add_bounded_wstring_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_bound, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_array_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_bound, array_length);
}
void
DynamicMessageTypeBuilder::add_bounded_string_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_unbounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_wstring_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_unbounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_string_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t string_bound, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_string_bounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
string_bound, sequence_bound);
}
void
DynamicMessageTypeBuilder::add_bounded_wstring_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
size_t wstring_bound, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_bounded_wstring_bounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
wstring_bound, sequence_bound);
}
// ADD NESTED MEMBERS ==============================================================================
void
DynamicMessageTypeBuilder::add_complex_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
nested_type.get_rosidl_dynamic_type());
}
void
DynamicMessageTypeBuilder::add_complex_array_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, size_t array_length, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_array_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
nested_type.get_rosidl_dynamic_type(), array_length);
}
void
DynamicMessageTypeBuilder::add_complex_unbounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_unbounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
nested_type.get_rosidl_dynamic_type());
}
void
DynamicMessageTypeBuilder::add_complex_bounded_sequence_member(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageType & nested_type, size_t sequence_bound, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_bounded_sequence_member(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
nested_type.get_rosidl_dynamic_type(), sequence_bound);
}
void
DynamicMessageTypeBuilder::add_complex_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_member_builder(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
nested_type_builder.get_rosidl_dynamic_type_builder());
}
void
DynamicMessageTypeBuilder::add_complex_array_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, size_t array_length,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_array_member_builder(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
nested_type_builder.get_rosidl_dynamic_type_builder(), array_length);
}
void
DynamicMessageTypeBuilder::add_complex_unbounded_sequence_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_unbounded_sequence_member_builder(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
nested_type_builder.get_rosidl_dynamic_type_builder());
}
void
DynamicMessageTypeBuilder::add_complex_bounded_sequence_member_builder(
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
DynamicMessageTypeBuilder & nested_type_builder, size_t sequence_bound,
const std::string & default_value)
{
rosidl_dynamic_typesupport_dynamic_type_builder_add_complex_bounded_sequence_member_builder(
get_rosidl_dynamic_type_builder(),
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(),
nested_type_builder.get_rosidl_dynamic_type_builder(), sequence_bound);
}

View File

@@ -0,0 +1,465 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <rosidl_dynamic_typesupport/identifier.h>
#include <rosidl_dynamic_typesupport/types.h>
#include <rosidl_runtime_c/message_type_support_struct.h>
#include <rosidl_runtime_c/type_description_utils.h>
#include <rosidl_runtime_c/type_description/type_description__functions.h>
#include <rosidl_runtime_c/type_description/type_description__struct.h>
#include <memory>
#include <string>
#include "rcl/allocator.h"
#include "rcl/dynamic_message_type_support.h"
#include "rcl/type_hash.h"
#include "rcl/types.h"
#include "rcutils/logging_macros.h"
#include "rcutils/types/rcutils_ret.h"
#include "rmw/dynamic_message_type_support.h"
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message_type_support.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
using rclcpp::dynamic_typesupport::DynamicMessage;
using rclcpp::dynamic_typesupport::DynamicMessageType;
using rclcpp::dynamic_typesupport::DynamicMessageTypeSupport;
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
// CONSTRUCTION ====================================================================================
DynamicMessageTypeSupport::DynamicMessageTypeSupport(
const rosidl_runtime_c__type_description__TypeDescription & description,
const std::string & serialization_library_name)
: serialization_support_(nullptr),
dynamic_message_type_(nullptr),
dynamic_message_(nullptr),
description_(nullptr),
rosidl_message_type_support_(nullptr)
{
rosidl_message_type_support_t * ts = nullptr;
rcl_ret_t ret;
if (serialization_library_name.empty()) {
ret = rcl_dynamic_message_type_support_handle_create(nullptr, &description, &ts);
} else {
ret = rcl_dynamic_message_type_support_handle_create(
serialization_library_name.c_str(), &description, &ts);
}
if (ret != RCL_RET_OK) {
throw std::runtime_error("error initializing rosidl message type support");
}
if (!ts) {
throw std::runtime_error("could not init rosidl message type support");
}
if (!ts->data) {
throw std::runtime_error("could not init rosidl message type support impl");
}
if (ts->typesupport_identifier != rosidl_get_dynamic_typesupport_identifier()) {
throw std::runtime_error("rosidl message type support is of the wrong type");
}
// NOTE(methylDragon): Not technically const correct, but since it's a const void *,
// we do it anyway...
auto ts_impl = static_cast<const rosidl_dynamic_message_type_support_impl_t *>(ts->data);
// NOTE(methylDragon): We don't destroy the rosidl_message_type_support->data since its members
// are managed by the passed in SharedPtr wrapper classes. We just delete it.
rosidl_message_type_support_.reset(
ts,
[](rosidl_message_type_support_t * ts) -> void {
auto ts_impl = static_cast<const rosidl_dynamic_message_type_support_impl_t *>(ts->data);
auto allocator = rcl_get_default_allocator();
// These are all C allocated
allocator.deallocate(ts_impl->type_hash, &allocator.state);
allocator.deallocate(
const_cast<rosidl_dynamic_message_type_support_impl_t *>(ts_impl), &allocator.state);
allocator.deallocate(ts, &allocator.state);
}
);
manage_description_(ts_impl->type_description);
serialization_support_ = DynamicSerializationSupport::make_shared(ts_impl->serialization_support);
dynamic_message_type_ = DynamicMessageType::make_shared(
get_shared_dynamic_serialization_support(), ts_impl->dynamic_message_type);
dynamic_message_ = DynamicMessage::make_shared(
get_shared_dynamic_serialization_support(), ts_impl->dynamic_message);
if (!rosidl_message_type_support_) {
throw std::runtime_error("could not init rosidl message type support.");
}
}
DynamicMessageTypeSupport::DynamicMessageTypeSupport(
DynamicSerializationSupport::SharedPtr serialization_support,
const rosidl_runtime_c__type_description__TypeDescription & description)
: serialization_support_(serialization_support),
dynamic_message_type_(nullptr),
dynamic_message_(nullptr),
description_(nullptr),
rosidl_message_type_support_(nullptr)
{
// Check null
if (!serialization_support) {
throw std::runtime_error("serialization_support cannot be nullptr.");
}
rosidl_message_type_support_t * ts = nullptr;
auto type_hash = std::make_unique<rosidl_type_hash_t>();
rcutils_ret_t hash_ret = rcl_calculate_type_hash(
// TODO(methylDragon): Swap this out with the conversion function when it is ready
reinterpret_cast<const type_description_interfaces__msg__TypeDescription *>(&description),
type_hash.get());
if (hash_ret != RCL_RET_OK || !type_hash) {
throw std::runtime_error("failed to get type hash");
}
rcutils_ret_t ret = rosidl_dynamic_message_type_support_handle_create(
serialization_support->get_rosidl_serialization_support(),
type_hash.get(), // type_hash
&description, // type_description
nullptr, // type_description_sources (not implemented for dynamic types)
&ts);
if (ret != RCUTILS_RET_OK || !ts) {
throw std::runtime_error("could not init rosidl message type support");
}
if (!ts->data) {
throw std::runtime_error("could not init rosidl message type support impl");
}
if (ts->typesupport_identifier != rosidl_get_dynamic_typesupport_identifier()) {
throw std::runtime_error("rosidl message type support is of the wrong type");
}
auto ts_impl = static_cast<const rosidl_dynamic_message_type_support_impl_t *>(ts->data);
// NOTE(methylDragon): We don't finalize the rosidl_message_type_support->data since its members
// are managed by the passed in SharedPtr wrapper classes. We just delete it.
rosidl_message_type_support_.reset(
ts,
[](rosidl_message_type_support_t * ts) -> void {
auto ts_impl = static_cast<const rosidl_dynamic_message_type_support_impl_t *>(ts->data);
// These are allocated with new
delete ts_impl->type_hash; // Only because we should've allocated it here
delete ts_impl;
delete ts;
}
);
manage_description_(ts_impl->type_description);
dynamic_message_type_ = DynamicMessageType::make_shared(
get_shared_dynamic_serialization_support(), ts_impl->dynamic_message_type);
dynamic_message_ = DynamicMessage::make_shared(
get_shared_dynamic_serialization_support(), ts_impl->dynamic_message);
if (!rosidl_message_type_support_) {
throw std::runtime_error("could not init rosidl message type support.");
}
type_hash.release();
}
DynamicMessageTypeSupport::DynamicMessageTypeSupport(
DynamicSerializationSupport::SharedPtr serialization_support,
DynamicMessageType::SharedPtr dynamic_message_type,
DynamicMessage::SharedPtr dynamic_message,
const rosidl_runtime_c__type_description__TypeDescription & description)
: serialization_support_(serialization_support),
dynamic_message_type_(dynamic_message_type),
dynamic_message_(dynamic_message),
description_(nullptr),
rosidl_message_type_support_(nullptr)
{
// Check null
if (!serialization_support) {
throw std::runtime_error("serialization_support cannot be nullptr.");
}
if (!dynamic_message_type) {
throw std::runtime_error("dynamic_message_type cannot be nullptr.");
}
if (!dynamic_message) {
throw std::runtime_error("dynamic_message cannot be nullptr.");
}
description_.reset(
new rosidl_runtime_c__type_description__TypeDescription(),
[](rosidl_runtime_c__type_description__TypeDescription * description) -> void {
rosidl_runtime_c__type_description__TypeDescription__destroy(description);
});
if (!description_) {
throw std::runtime_error("could not init type description.");
}
if (!rosidl_runtime_c__type_description__TypeDescription__copy(
&description,
description_.get()))
{
throw std::runtime_error("could not copy type description.");
}
// Check identifiers
if (serialization_support->get_library_identifier() !=
dynamic_message_type->get_library_identifier())
{
throw std::runtime_error(
"serialization support library identifier does not match "
"dynamic message type library identifier.");
}
if (dynamic_message_type->get_library_identifier() != dynamic_message->get_library_identifier()) {
throw std::runtime_error(
"dynamic message type library identifier does not match "
"dynamic message library identifier.");
}
// Check pointers
/* *INDENT-OFF* */
if (serialization_support->get_rosidl_serialization_support() !=
dynamic_message_type
->get_shared_dynamic_serialization_support()
->get_rosidl_serialization_support())
{
throw std::runtime_error("serialization support pointer does not match dynamic message type's");
}
if (dynamic_message_type
->get_shared_dynamic_serialization_support()
->get_rosidl_serialization_support() !=
dynamic_message_type
->get_shared_dynamic_serialization_support()
->get_rosidl_serialization_support())
{
throw std::runtime_error("serialization support does not match pointer dynamic message type's");
}
/* *INDENT-ON* */
init_rosidl_message_type_support_(
serialization_support_, dynamic_message_type_, dynamic_message_, description_.get());
if (!rosidl_message_type_support_) {
throw std::runtime_error("could not init rosidl message type support.");
}
}
DynamicMessageTypeSupport::~DynamicMessageTypeSupport() {}
void
DynamicMessageTypeSupport::manage_description_(
rosidl_runtime_c__type_description__TypeDescription * description)
{
if (!description) {
throw std::runtime_error("description cannot be nullptr");
}
description_.reset(
description,
[](rosidl_runtime_c__type_description__TypeDescription * description) -> void {
rosidl_runtime_c__type_description__TypeDescription__destroy(description);
});
}
// This looks like rmw_`dynamic_message_type_support_handle_create()`, but instead just aggregates
// already initialized objects
void
DynamicMessageTypeSupport::init_rosidl_message_type_support_(
DynamicSerializationSupport::SharedPtr serialization_support,
DynamicMessageType::SharedPtr dynamic_message_type,
DynamicMessage::SharedPtr dynamic_message,
rosidl_runtime_c__type_description__TypeDescription * description)
{
bool middleware_supports_type_discovery = rmw_feature_supported(
RMW_MIDDLEWARE_SUPPORTS_TYPE_DISCOVERY);
if (!middleware_supports_type_discovery && !description) {
throw std::runtime_error(
"Middleware does not support type discovery! Deferred dynamic type"
"message type support will never be populated! You must provide a type "
"description.");
return;
}
auto type_hash = std::make_unique<rosidl_type_hash_t>();
rcutils_ret_t hash_ret = rcl_calculate_type_hash(
// TODO(methylDragon): Swap this out with the conversion function when it is ready
// from https://github.com/ros2/rcl/pull/1052
reinterpret_cast<type_description_interfaces__msg__TypeDescription *>(description),
type_hash.get());
if (hash_ret != RCL_RET_OK || !type_hash) {
throw std::runtime_error("failed to get type hash");
}
rosidl_dynamic_message_type_support_impl_t * ts_impl =
new rosidl_dynamic_message_type_support_impl_t {
type_hash.get(), // type_hash
description, // type_description
nullptr, // NOTE(methylDragon): Not supported for now // type_description_sources
serialization_support->get_rosidl_serialization_support(), // serialization_support
dynamic_message_type->get_rosidl_dynamic_type(), // dynamic_message_type
dynamic_message->get_rosidl_dynamic_data() // dynamic_message
};
if (!ts_impl) {
throw std::runtime_error(
"Could not allocate rosidl_dynamic_message_type_support_impl_t struct");
return;
}
// NOTE(methylDragon): We don't finalize the rosidl_message_type_support->data since its members
// are managed by the passed in SharedPtr wrapper classes. We just delete it.
rosidl_message_type_support_.reset(
new rosidl_message_type_support_t{
rosidl_get_dynamic_typesupport_identifier(), // typesupport_identifier
ts_impl, // data
get_message_typesupport_handle_function, // func
// get_type_hash_func
rosidl_get_dynamic_message_type_support_type_hash_function,
// get_type_description_func
rosidl_get_dynamic_message_type_support_type_description_function,
// get_type_description_sources_func
rosidl_get_dynamic_message_type_support_type_description_sources_function
},
[](rosidl_message_type_support_t * ts) -> void {
auto ts_impl = static_cast<const rosidl_dynamic_message_type_support_impl_t *>(ts->data);
auto allocator = rcl_get_default_allocator();
// Only because we should've allocated it here (also it's C allocated)
allocator.deallocate(ts_impl->type_hash, &allocator.state);
delete ts_impl;
}
);
if (!rosidl_message_type_support_) {
throw std::runtime_error("Could not allocate rosidl_message_type_support_t struct");
delete ts_impl;
return;
}
type_hash.release();
}
// GETTERS =========================================================================================
const std::string
DynamicMessageTypeSupport::get_library_identifier() const
{
return serialization_support_->get_library_identifier();
}
rosidl_message_type_support_t *
DynamicMessageTypeSupport::get_rosidl_message_type_support()
{
return rosidl_message_type_support_.get();
}
const rosidl_message_type_support_t *
DynamicMessageTypeSupport::get_rosidl_message_type_support() const
{
return rosidl_message_type_support_.get();
}
std::shared_ptr<rosidl_message_type_support_t>
DynamicMessageTypeSupport::get_shared_rosidl_message_type_support()
{
return rosidl_message_type_support_;
}
std::shared_ptr<const rosidl_message_type_support_t>
DynamicMessageTypeSupport::get_shared_rosidl_message_type_support() const
{
return rosidl_message_type_support_;
}
rosidl_runtime_c__type_description__TypeDescription *
DynamicMessageTypeSupport::get_rosidl_runtime_c_type_description()
{
return description_.get();
}
const rosidl_runtime_c__type_description__TypeDescription *
DynamicMessageTypeSupport::get_rosidl_runtime_c_type_description() const
{
return description_.get();
}
std::shared_ptr<rosidl_runtime_c__type_description__TypeDescription>
DynamicMessageTypeSupport::get_shared_rosidl_runtime_c_type_description()
{
return description_;
}
std::shared_ptr<const rosidl_runtime_c__type_description__TypeDescription>
DynamicMessageTypeSupport::get_shared_rosidl_runtime_c_type_description() const
{
return description_;
}
DynamicSerializationSupport::SharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_serialization_support()
{
return serialization_support_;
}
DynamicSerializationSupport::ConstSharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_serialization_support() const
{
return serialization_support_;
}
DynamicMessageType::SharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_message_type()
{
return dynamic_message_type_;
}
DynamicMessageType::ConstSharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_message_type() const
{
return dynamic_message_type_;
}
DynamicMessage::SharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_message()
{
return dynamic_message_;
}
DynamicMessage::ConstSharedPtr
DynamicMessageTypeSupport::get_shared_dynamic_message() const
{
return dynamic_message_;
}

View File

@@ -0,0 +1,136 @@
// Copyright 2023 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <rosidl_dynamic_typesupport/api/serialization_support.h>
#include <memory>
#include <string>
#include "rcutils/logging_macros.h"
#include "rmw/dynamic_message_type_support.h"
#include "rmw/ret_types.h"
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
#include "rclcpp/exceptions.hpp"
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
// CONSTRUCTION ====================================================================================
DynamicSerializationSupport::DynamicSerializationSupport()
: DynamicSerializationSupport::DynamicSerializationSupport("") {}
DynamicSerializationSupport::DynamicSerializationSupport(
const std::string & serialization_library_name)
: rosidl_serialization_support_(nullptr)
{
rosidl_dynamic_typesupport_serialization_support_t * rosidl_serialization_support = nullptr;
rmw_ret_t ret = RMW_RET_ERROR;
if (serialization_library_name.empty()) {
ret = rmw_get_serialization_support(NULL, &rosidl_serialization_support);
} else {
ret = rmw_get_serialization_support(
serialization_library_name.c_str(), &rosidl_serialization_support);
}
if (ret != RMW_RET_OK || !rosidl_serialization_support) {
throw std::runtime_error("could not create new serialization support object");
}
rosidl_serialization_support_.reset(
rosidl_serialization_support,
// Custom deleter
[](rosidl_dynamic_typesupport_serialization_support_t * rosidl_serialization_support) -> void {
rosidl_dynamic_typesupport_serialization_support_destroy(rosidl_serialization_support);
});
}
DynamicSerializationSupport::DynamicSerializationSupport(
rosidl_dynamic_typesupport_serialization_support_t * rosidl_serialization_support)
: rosidl_serialization_support_(nullptr)
{
if (!rosidl_serialization_support) {
throw std::runtime_error("serialization support cannot be nullptr!");
}
// Custom deleter
rosidl_serialization_support_.reset(
rosidl_serialization_support,
[](rosidl_dynamic_typesupport_serialization_support_t * rosidl_serialization_support) -> void {
rosidl_dynamic_typesupport_serialization_support_destroy(rosidl_serialization_support);
});
}
DynamicSerializationSupport::DynamicSerializationSupport(
std::shared_ptr<rosidl_dynamic_typesupport_serialization_support_t> rosidl_serialization_support)
: rosidl_serialization_support_(rosidl_serialization_support) {}
DynamicSerializationSupport::DynamicSerializationSupport(
DynamicSerializationSupport && other) noexcept
: rosidl_serialization_support_(std::exchange(other.rosidl_serialization_support_, nullptr)) {}
DynamicSerializationSupport &
DynamicSerializationSupport::operator=(DynamicSerializationSupport && other) noexcept
{
std::swap(rosidl_serialization_support_, other.rosidl_serialization_support_);
return *this;
}
DynamicSerializationSupport::~DynamicSerializationSupport() {}
// GETTERS =========================================================================================
const std::string
DynamicSerializationSupport::get_library_identifier() const
{
return std::string(
rosidl_dynamic_typesupport_serialization_support_get_library_identifier(
rosidl_serialization_support_.get()));
}
rosidl_dynamic_typesupport_serialization_support_t *
DynamicSerializationSupport::get_rosidl_serialization_support()
{
return rosidl_serialization_support_.get();
}
const rosidl_dynamic_typesupport_serialization_support_t *
DynamicSerializationSupport::get_rosidl_serialization_support() const
{
return rosidl_serialization_support_.get();
}
std::shared_ptr<rosidl_dynamic_typesupport_serialization_support_t>
DynamicSerializationSupport::get_shared_rosidl_serialization_support()
{
return std::shared_ptr<rosidl_dynamic_typesupport_serialization_support_t>(
shared_from_this(), rosidl_serialization_support_.get());
}
std::shared_ptr<const rosidl_dynamic_typesupport_serialization_support_t>
DynamicSerializationSupport::get_shared_rosidl_serialization_support() const
{
return std::shared_ptr<const rosidl_dynamic_typesupport_serialization_support_t>(
shared_from_this(), rosidl_serialization_support_.get());
}

View File

@@ -12,9 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdexcept>
#include <string>
#include "rclcpp/qos_event.hpp"
#include "rcl/event.h"
#include "rclcpp/event_handler.hpp"
#include "rclcpp/exceptions/exceptions.hpp"
namespace rclcpp
{
@@ -33,16 +37,14 @@ UnsupportedEventTypeException::UnsupportedEventTypeException(
std::runtime_error(prefix + (prefix.empty() ? "" : ": ") + base_exc.formatted_message)
{}
QOSEventHandlerBase::~QOSEventHandlerBase()
EventHandlerBase::~EventHandlerBase()
{
// Since the rmw event listener holds a reference to
// this callback, we need to clear it on destruction of this class.
// This clearing is not needed for other rclcpp entities like pub/subs, since
// they do own the underlying rmw entities, which are destroyed
// on their rclcpp destructors, thus no risk of dangling pointers.
if (on_new_event_callback_) {
clear_on_ready_callback();
}
clear_on_ready_callback();
if (rcl_event_fini(&event_handle_) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
@@ -54,14 +56,14 @@ QOSEventHandlerBase::~QOSEventHandlerBase()
/// Get the number of ready events.
size_t
QOSEventHandlerBase::get_number_of_ready_events()
EventHandlerBase::get_number_of_ready_events()
{
return 1;
}
/// Add the Waitable to a wait set.
void
QOSEventHandlerBase::add_to_wait_set(rcl_wait_set_t * wait_set)
EventHandlerBase::add_to_wait_set(rcl_wait_set_t * wait_set)
{
rcl_ret_t ret = rcl_wait_set_add_event(wait_set, &event_handle_, &wait_set_event_index_);
if (RCL_RET_OK != ret) {
@@ -71,13 +73,13 @@ QOSEventHandlerBase::add_to_wait_set(rcl_wait_set_t * wait_set)
/// Check if the Waitable is ready.
bool
QOSEventHandlerBase::is_ready(rcl_wait_set_t * wait_set)
EventHandlerBase::is_ready(rcl_wait_set_t * wait_set)
{
return wait_set->events[wait_set_event_index_] == &event_handle_;
}
void
QOSEventHandlerBase::set_on_new_event_callback(
EventHandlerBase::set_on_new_event_callback(
rcl_event_callback_t callback,
const void * user_data)
{
@@ -88,7 +90,7 @@ QOSEventHandlerBase::set_on_new_event_callback(
if (RCL_RET_OK != ret) {
using rclcpp::exceptions::throw_from_rcl_error;
throw_from_rcl_error(ret, "failed to set the on new message callback for QOS Event");
throw_from_rcl_error(ret, "failed to set the on new message callback for Event");
}
}

View File

@@ -24,6 +24,7 @@
#include "rcl/error_handling.h"
#include "rcpputils/scope_exit.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/executor.hpp"
#include "rclcpp/guard_condition.hpp"
@@ -558,13 +559,14 @@ Executor::execute_any_executable(AnyExecutable & any_exec)
}
}
template<typename Taker, typename Handler>
static
void
take_and_do_error_handling(
const char * action_description,
const char * topic_or_service_name,
std::function<bool()> take_action,
std::function<void()> handle_action)
Taker take_action,
Handler handle_action)
{
bool taken = false;
try {
@@ -597,70 +599,136 @@ take_and_do_error_handling(
void
Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
{
using rclcpp::dynamic_typesupport::DynamicMessage;
rclcpp::MessageInfo message_info;
message_info.get_rmw_message_info().from_intra_process = false;
if (subscription->is_serialized()) {
// This is the case where a copy of the serialized message is taken from
// the middleware via inter-process communication.
std::shared_ptr<SerializedMessage> serialized_msg = subscription->create_serialized_message();
take_and_do_error_handling(
"taking a serialized message from topic",
subscription->get_topic_name(),
[&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
[&]()
switch (subscription->get_subscription_type()) {
// Take ROS message
case rclcpp::SubscriptionType::ROS_MESSAGE:
{
subscription->handle_serialized_message(serialized_msg, message_info);
});
subscription->return_serialized_message(serialized_msg);
} else if (subscription->can_loan_messages()) {
// This is the case where a loaned message is taken from the middleware via
// inter-process communication, given to the user for their callback,
// and then returned.
void * loaned_msg = nullptr;
// TODO(wjwwood): refactor this into methods on subscription when LoanedMessage
// is extened to support subscriptions as well.
take_and_do_error_handling(
"taking a loaned message from topic",
subscription->get_topic_name(),
[&]()
{
rcl_ret_t ret = rcl_take_loaned_message(
subscription->get_subscription_handle().get(),
&loaned_msg,
&message_info.get_rmw_message_info(),
nullptr);
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
return false;
} else if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
if (subscription->can_loan_messages()) {
// This is the case where a loaned message is taken from the middleware via
// inter-process communication, given to the user for their callback,
// and then returned.
void * loaned_msg = nullptr;
// TODO(wjwwood): refactor this into methods on subscription when LoanedMessage
// is extened to support subscriptions as well.
take_and_do_error_handling(
"taking a loaned message from topic",
subscription->get_topic_name(),
[&]()
{
rcl_ret_t ret = rcl_take_loaned_message(
subscription->get_subscription_handle().get(),
&loaned_msg,
&message_info.get_rmw_message_info(),
nullptr);
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
return false;
} else if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
return true;
},
[&]() {subscription->handle_loaned_message(loaned_msg, message_info);});
if (nullptr != loaned_msg) {
rcl_ret_t ret = rcl_return_loaned_message_from_subscription(
subscription->get_subscription_handle().get(), loaned_msg);
if (RCL_RET_OK != ret) {
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),
"rcl_return_loaned_message_from_subscription() failed for subscription on topic "
"'%s': %s",
subscription->get_topic_name(), rcl_get_error_string().str);
}
loaned_msg = nullptr;
}
} else {
// This case is taking a copy of the message data from the middleware via
// inter-process communication.
std::shared_ptr<void> message = subscription->create_message();
take_and_do_error_handling(
"taking a message from topic",
subscription->get_topic_name(),
[&]() {return subscription->take_type_erased(message.get(), message_info);},
[&]() {subscription->handle_message(message, message_info);});
subscription->return_message(message);
}
return true;
},
[&]() {subscription->handle_loaned_message(loaned_msg, message_info);});
if (nullptr != loaned_msg) {
rcl_ret_t ret = rcl_return_loaned_message_from_subscription(
subscription->get_subscription_handle().get(),
loaned_msg);
if (RCL_RET_OK != ret) {
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),
"rcl_return_loaned_message_from_subscription() failed for subscription on topic '%s': %s",
subscription->get_topic_name(), rcl_get_error_string().str);
break;
}
// Take serialized message
case rclcpp::SubscriptionType::SERIALIZED_MESSAGE:
{
// This is the case where a copy of the serialized message is taken from
// the middleware via inter-process communication.
std::shared_ptr<SerializedMessage> serialized_msg =
subscription->create_serialized_message();
take_and_do_error_handling(
"taking a serialized message from topic",
subscription->get_topic_name(),
[&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
[&]()
{
subscription->handle_serialized_message(serialized_msg, message_info);
});
subscription->return_serialized_message(serialized_msg);
break;
}
// DYNAMIC SUBSCRIPTION ========================================================================
// If a subscription is dynamic, then it will use its serialization-specific dynamic data.
//
// Two cases:
// - Dynamic type subscription using dynamic type stored in its own internal type support struct
// - Non-dynamic type subscription with no stored dynamic type
// - Subscriptions of this type must be able to lookup the local message description to
// generate a dynamic type at runtime!
// - TODO(methylDragon): I won't be handling this case yet
// Take dynamic message directly from the middleware
case rclcpp::SubscriptionType::DYNAMIC_MESSAGE_DIRECT:
{
DynamicMessage::SharedPtr dynamic_message = subscription->create_dynamic_message();
take_and_do_error_handling(
"taking a dynamic message from topic",
subscription->get_topic_name(),
// This modifies the stored dynamic data in the DynamicMessage in-place
[&]() {return subscription->take_dynamic_message(*dynamic_message, message_info);},
[&]() {subscription->handle_dynamic_message(dynamic_message, message_info);});
subscription->return_dynamic_message(dynamic_message);
break;
}
// Take serialized and then convert to dynamic message
case rclcpp::SubscriptionType::DYNAMIC_MESSAGE_FROM_SERIALIZED:
{
std::shared_ptr<SerializedMessage> serialized_msg =
subscription->create_serialized_message();
// NOTE(methylDragon): Is this clone necessary? If I'm following the pattern, it seems so.
DynamicMessage::SharedPtr dynamic_message = subscription->create_dynamic_message();
take_and_do_error_handling(
"taking a serialized message from topic",
subscription->get_topic_name(),
[&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
[&]()
{
bool ret = dynamic_message->deserialize(&serialized_msg->get_rcl_serialized_message());
if (!ret) {
throw_from_rcl_error(ret, "Couldn't convert serialized message to dynamic data!");
}
subscription->handle_dynamic_message(dynamic_message, message_info);
}
);
subscription->return_serialized_message(serialized_msg);
subscription->return_dynamic_message(dynamic_message);
break;
}
loaned_msg = nullptr;
}
} else {
// This case is taking a copy of the message data from the middleware via
// inter-process communication.
std::shared_ptr<void> message = subscription->create_message();
take_and_do_error_handling(
"taking a message from topic",
subscription->get_topic_name(),
[&]() {return subscription->take_type_erased(message.get(), message_info);},
[&]() {subscription->handle_message(message, message_info);});
subscription->return_message(message);
}
return;
}
void

View File

@@ -43,8 +43,7 @@ void GenericSubscription::handle_message(
"handle_message is not implemented for GenericSubscription");
}
void
GenericSubscription::handle_serialized_message(
void GenericSubscription::handle_serialized_message(
const std::shared_ptr<rclcpp::SerializedMessage> & message,
const rclcpp::MessageInfo &)
{
@@ -72,4 +71,55 @@ void GenericSubscription::return_serialized_message(
message.reset();
}
// DYNAMIC TYPE ====================================================================================
// TODO(methylDragon): Reorder later
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
GenericSubscription::get_shared_dynamic_message_type()
{
throw rclcpp::exceptions::UnimplementedError(
"get_shared_dynamic_message_type is not implemented for GenericSubscription");
}
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
GenericSubscription::get_shared_dynamic_message()
{
throw rclcpp::exceptions::UnimplementedError(
"get_shared_dynamic_message is not implemented for GenericSubscription");
}
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
GenericSubscription::get_shared_dynamic_serialization_support()
{
throw rclcpp::exceptions::UnimplementedError(
"get_shared_dynamic_serialization_support is not implemented for GenericSubscription");
}
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
GenericSubscription::create_dynamic_message()
{
throw rclcpp::exceptions::UnimplementedError(
"create_dynamic_message is not implemented for GenericSubscription");
}
void
GenericSubscription::return_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
{
(void) message;
throw rclcpp::exceptions::UnimplementedError(
"return_dynamic_message is not implemented for GenericSubscription");
}
void
GenericSubscription::handle_dynamic_message(
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
const rclcpp::MessageInfo & message_info)
{
(void) message;
(void) message_info;
throw rclcpp::exceptions::UnimplementedError(
"handle_dynamic_message is not implemented for GenericSubscription");
}
} // namespace rclcpp

View File

@@ -12,14 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include <string>
#include <utility>
#include "rcl_logging_interface/rcl_logging_interface.h"
#include "rcl/logging_rosout.h"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/logging.hpp"
#include "./logging_mutex.hpp"
namespace rclcpp
{
@@ -62,6 +67,46 @@ get_logging_directory()
return path;
}
Logger
Logger::get_child(const std::string & suffix)
{
if (!name_) {
return Logger();
}
rcl_ret_t rcl_ret = RCL_RET_OK;
std::shared_ptr<std::recursive_mutex> logging_mutex;
logging_mutex = get_global_logging_mutex();
{
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
rcl_ret = rcl_logging_rosout_add_sublogger((*name_).c_str(), suffix.c_str());
if (RCL_RET_OK != rcl_ret) {
exceptions::throw_from_rcl_error(
rcl_ret, "failed to call rcl_logging_rosout_add_sublogger",
rcutils_get_error_state(), rcutils_reset_error);
}
}
Logger logger(*name_ + RCUTILS_LOGGING_SEPARATOR_STRING + suffix);
if (RCL_RET_OK == rcl_ret) {
logger.logger_sublogger_pairname_.reset(
new std::pair<std::string, std::string>({*name_, suffix}),
[logging_mutex](std::pair<std::string, std::string> * logger_sublogger_pairname_ptr) {
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
rcl_ret_t rcl_ret = rcl_logging_rosout_remove_sublogger(
logger_sublogger_pairname_ptr->first.c_str(),
logger_sublogger_pairname_ptr->second.c_str());
delete logger_sublogger_pairname_ptr;
if (RCL_RET_OK != rcl_ret) {
exceptions::throw_from_rcl_error(
rcl_ret, "failed to call rcl_logging_rosout_remove_sublogger",
rcutils_get_error_state(), rcutils_reset_error);
}
});
}
return logger;
}
void
Logger::set_level(Level level)
{
@@ -80,4 +125,18 @@ Logger::set_level(Level level)
}
}
Logger::Level
Logger::get_effective_level() const
{
int logger_level = rcutils_logging_get_logger_effective_level(get_name());
if (logger_level < 0) {
exceptions::throw_from_rcl_error(
RCL_RET_ERROR, "Couldn't get logger level",
rcutils_get_error_state(), rcutils_reset_error);
}
return static_cast<Level>(logger_level);
}
} // namespace rclcpp

View File

@@ -651,7 +651,7 @@ NodeParameters::undeclare_parameter(const std::string & name)
}
if (!parameter_info->second.descriptor.dynamic_typing) {
throw rclcpp::exceptions::InvalidParameterTypeException{
name, "cannot undeclare an statically typed parameter"};
name, "cannot undeclare a statically typed parameter"};
}
parameters_.erase(parameter_info);
@@ -824,7 +824,7 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
auto it = parameters_.find(parameter.get_name());
if (it != parameters_.end() && rclcpp::PARAMETER_NOT_SET != it->second.value.get_type()) {
if (!it->second.descriptor.dynamic_typing) {
result.reason = "cannot undeclare an statically typed parameter";
result.reason = "cannot undeclare a statically typed parameter";
result.successful = false;
return result;
}

View File

@@ -37,7 +37,7 @@
#include "rclcpp/macros.hpp"
#include "rclcpp/network_flow_endpoint.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/event_handler.hpp"
using rclcpp::PublisherBase;
@@ -145,21 +145,48 @@ PublisherBase::bind_event_callbacks(
event_callbacks.liveliness_callback,
RCL_PUBLISHER_LIVELINESS_LOST);
}
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_cb;
if (event_callbacks.incompatible_qos_callback) {
this->add_event_handler(
event_callbacks.incompatible_qos_callback,
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
incompatible_qos_cb = event_callbacks.incompatible_qos_callback;
} else if (use_default_callbacks) {
// Register default callback when not specified
try {
this->add_event_handler(
[this](QOSOfferedIncompatibleQoSInfo & info) {
this->default_incompatible_qos_callback(info);
},
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
} catch (UnsupportedEventTypeException & /*exc*/) {
// pass
incompatible_qos_cb = [this](QOSOfferedIncompatibleQoSInfo & info) {
this->default_incompatible_qos_callback(info);
};
}
try {
if (incompatible_qos_cb) {
this->add_event_handler(incompatible_qos_cb, RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
RCLCPP_DEBUG(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for incompatible qos; wrong callback type");
}
IncompatibleTypeCallbackType incompatible_type_cb;
if (event_callbacks.incompatible_type_callback) {
incompatible_type_cb = event_callbacks.incompatible_type_callback;
} else if (use_default_callbacks) {
// Register default callback when not specified
incompatible_type_cb = [this](IncompatibleTypeInfo & info) {
this->default_incompatible_type_callback(info);
};
}
try {
if (incompatible_type_cb) {
this->add_event_handler(incompatible_type_cb, RCL_PUBLISHER_INCOMPATIBLE_TYPE);
}
} catch (UnsupportedEventTypeException & /*exc*/) {
RCLCPP_DEBUG(
rclcpp::get_logger("rclcpp"),
"Failed to add event handler for incompatible type; wrong callback type");
}
if (event_callbacks.matched_callback) {
this->add_event_handler(
event_callbacks.matched_callback,
RCL_PUBLISHER_MATCHED);
}
}
@@ -195,7 +222,7 @@ PublisherBase::get_publisher_handle() const
}
const
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
PublisherBase::get_event_handlers() const
{
return event_handlers_;
@@ -265,7 +292,7 @@ PublisherBase::assert_liveliness() const
bool
PublisherBase::can_loan_messages() const
{
return rcl_publisher_can_loan_messages(publisher_handle_.get());
return !intra_process_is_enabled_ && rcl_publisher_can_loan_messages(publisher_handle_.get());
}
bool
@@ -311,6 +338,17 @@ PublisherBase::default_incompatible_qos_callback(
policy_name.c_str());
}
void
PublisherBase::default_incompatible_type_callback(
rclcpp::IncompatibleTypeInfo & event) const
{
(void)event;
RCLCPP_WARN(
rclcpp::get_logger(rcl_node_get_logger_name(rcl_node_handle_.get())),
"Incompatible type on topic '%s', no messages will be sent to it.", get_topic_name());
}
std::vector<rclcpp::NetworkFlowEndpoint> PublisherBase::get_network_flow_endpoints() const
{
rcutils_allocator_t allocator = rcutils_get_default_allocator();

View File

@@ -22,6 +22,7 @@
#include "rclcpp/any_service_callback.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/qos.hpp"
#include "rmw/error_handling.h"
#include "rmw/rmw.h"
@@ -131,7 +132,7 @@ ServiceBase::set_on_new_request_callback(rcl_event_callback_t callback, const vo
user_data);
if (RCL_RET_OK != ret) {
using rclcpp::exceptions::throw_from_rcl_error;
throw_from_rcl_error(ret, "failed to set the on new request callback for service");
rclcpp::exceptions::throw_from_rcl_error(
ret, "failed to set the on new request callback for service");
}
}

View File

@@ -22,16 +22,19 @@
#include "rcpputils/scope_exit.hpp"
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
#include "rclcpp/experimental/intra_process_manager.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/event_handler.hpp"
#include "rmw/error_handling.h"
#include "rmw/rmw.h"
#include "rosidl_dynamic_typesupport/types.h"
using rclcpp::SubscriptionBase;
SubscriptionBase::SubscriptionBase(
@@ -41,7 +44,7 @@ SubscriptionBase::SubscriptionBase(
const rcl_subscription_options_t & subscription_options,
const SubscriptionEventCallbacks & event_callbacks,
bool use_default_callbacks,
bool is_serialized)
SubscriptionType subscription_type)
: node_base_(node_base),
node_handle_(node_base_->get_shared_rcl_node_handle()),
node_logger_(rclcpp::get_node_logger(node_handle_.get())),
@@ -49,8 +52,16 @@ SubscriptionBase::SubscriptionBase(
intra_process_subscription_id_(0),
event_callbacks_(event_callbacks),
type_support_(type_support_handle),
is_serialized_(is_serialized)
subscription_type_(subscription_type)
{
if (!rmw_feature_supported(RMW_MIDDLEWARE_CAN_TAKE_DYNAMIC_MESSAGE) &&
subscription_type == rclcpp::SubscriptionType::DYNAMIC_MESSAGE_DIRECT)
{
throw std::runtime_error(
"Cannot set subscription to take dynamic message directly, feature not supported in rmw"
);
}
auto custom_deletor = [node_handle = this->node_handle_](rcl_subscription_t * rcl_subs)
{
if (rcl_subscription_fini(rcl_subs, node_handle.get()) != RCL_RET_OK) {
@@ -114,32 +125,58 @@ SubscriptionBase::bind_event_callbacks(
event_callbacks.deadline_callback,
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
}
if (event_callbacks.liveliness_callback) {
this->add_event_handler(
event_callbacks.liveliness_callback,
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
}
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_cb;
if (event_callbacks.incompatible_qos_callback) {
this->add_event_handler(
event_callbacks.incompatible_qos_callback,
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
incompatible_qos_cb = event_callbacks.incompatible_qos_callback;
} else if (use_default_callbacks) {
// Register default callback when not specified
try {
this->add_event_handler(
[this](QOSRequestedIncompatibleQoSInfo & info) {
this->default_incompatible_qos_callback(info);
},
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
} catch (UnsupportedEventTypeException & /*exc*/) {
// pass
}
incompatible_qos_cb = [this](QOSRequestedIncompatibleQoSInfo & info) {
this->default_incompatible_qos_callback(info);
};
}
// Register default callback when not specified
try {
if (incompatible_qos_cb) {
this->add_event_handler(incompatible_qos_cb, RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
}
} catch (const UnsupportedEventTypeException & /*exc*/) {
// pass
}
IncompatibleTypeCallbackType incompatible_type_cb;
if (event_callbacks.incompatible_type_callback) {
incompatible_type_cb = event_callbacks.incompatible_type_callback;
} else if (use_default_callbacks) {
// Register default callback when not specified
incompatible_type_cb = [this](IncompatibleTypeInfo & info) {
this->default_incompatible_type_callback(info);
};
}
try {
if (incompatible_type_cb) {
this->add_event_handler(incompatible_type_cb, RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE);
}
} catch (UnsupportedEventTypeException & /*exc*/) {
// pass
}
if (event_callbacks.message_lost_callback) {
this->add_event_handler(
event_callbacks.message_lost_callback,
RCL_SUBSCRIPTION_MESSAGE_LOST);
}
if (event_callbacks.matched_callback) {
this->add_event_handler(
event_callbacks.matched_callback,
RCL_SUBSCRIPTION_MATCHED);
}
}
const char *
@@ -161,7 +198,7 @@ SubscriptionBase::get_subscription_handle() const
}
const
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
SubscriptionBase::get_event_handlers() const
{
return event_handlers_;
@@ -229,10 +266,10 @@ SubscriptionBase::get_message_type_support_handle() const
return type_support_;
}
bool
SubscriptionBase::is_serialized() const
rclcpp::SubscriptionType
SubscriptionBase::get_subscription_type() const
{
return is_serialized_;
return subscription_type_;
}
size_t
@@ -299,6 +336,17 @@ SubscriptionBase::default_incompatible_qos_callback(
policy_name.c_str());
}
void
SubscriptionBase::default_incompatible_type_callback(
rclcpp::IncompatibleTypeInfo & event) const
{
(void)event;
RCLCPP_WARN(
rclcpp::get_logger(rcl_node_get_logger_name(node_handle_.get())),
"Incompatible type on topic '%s', no messages will be sent to it.", get_topic_name());
}
bool
SubscriptionBase::matches_any_intra_process_publishers(const rmw_gid_t * sender_gid) const
{
@@ -405,8 +453,7 @@ SubscriptionBase::set_content_filter(
rcl_subscription_content_filter_options_t options =
rcl_get_zero_initialized_subscription_content_filter_options();
std::vector<const char *> cstrings =
get_c_vector_string(expression_parameters);
std::vector<const char *> cstrings = get_c_vector_string(expression_parameters);
rcl_ret_t ret = rcl_subscription_content_filter_options_init(
subscription_handle_.get(),
get_c_string(filter_expression),
@@ -478,3 +525,24 @@ SubscriptionBase::get_content_filter() const
return ret_options;
}
// DYNAMIC TYPE ==================================================================================
// TODO(methylDragon): Reorder later
bool
SubscriptionBase::take_dynamic_message(
rclcpp::dynamic_typesupport::DynamicMessage & message_out,
rclcpp::MessageInfo & message_info_out)
{
rcl_ret_t ret = rcl_take_dynamic_message(
this->get_subscription_handle().get(),
message_out.get_rosidl_dynamic_data(),
&message_info_out.get_rmw_message_info(),
nullptr);
if (RCL_RET_SUBSCRIPTION_TAKE_FAILED == ret) {
return false;
} else if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
return true;
}

View File

@@ -444,17 +444,23 @@ function(test_generic_pubsub_for_rmw_implementation)
endif()
endfunction()
call_for_each_rmw_implementation(test_generic_pubsub_for_rmw_implementation)
ament_add_gtest(test_qos_event test_qos_event.cpp)
if(TARGET test_qos_event)
ament_target_dependencies(test_qos_event
"rmw"
"test_msgs"
function(test_qos_event_for_rmw_implementation)
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
ament_add_gmock(test_qos_event${target_suffix} test_qos_event.cpp
ENV ${rmw_implementation_env_var}
)
target_link_libraries(test_qos_event
${PROJECT_NAME}
mimick
)
endif()
if(TARGET test_qos_event${target_suffix})
target_link_libraries(test_qos_event${target_suffix} ${PROJECT_NAME} mimick)
ament_target_dependencies(test_qos_event${target_suffix}
"rmw"
"rosidl_typesupport_cpp"
"test_msgs"
)
endif()
endfunction()
call_for_each_rmw_implementation(test_qos_event_for_rmw_implementation)
ament_add_gmock(test_qos_overriding_options test_qos_overriding_options.cpp)
if(TARGET test_qos_overriding_options)
target_link_libraries(test_qos_overriding_options
@@ -508,6 +514,17 @@ if(TARGET test_service)
)
target_link_libraries(test_service ${PROJECT_NAME} mimick)
endif()
ament_add_gmock(test_service_introspection test_service_introspection.cpp)
if(TARGET test_service)
ament_target_dependencies(test_service_introspection
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_service_introspection ${PROJECT_NAME} mimick)
endif()
# Creating and destroying nodes is slow with Connext, so this needs larger timeout.
ament_add_gtest(test_subscription test_subscription.cpp TIMEOUT 120)
if(TARGET test_subscription)
@@ -739,6 +756,12 @@ if(TARGET test_rosout_qos)
target_link_libraries(test_rosout_qos ${PROJECT_NAME})
endif()
ament_add_gtest(test_rosout_subscription test_rosout_subscription.cpp)
if(TARGET test_rosout_subscription)
ament_target_dependencies(test_rosout_subscription "rcl")
target_link_libraries(test_rosout_subscription ${PROJECT_NAME})
endif()
ament_add_gtest(test_executor test_executor.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}"
TIMEOUT 120)

View File

@@ -28,6 +28,11 @@
#include "../../mocking_utils/patch.hpp"
#include "../../utils/rclcpp_gtest_macros.hpp"
using rclcpp::dynamic_typesupport::DynamicMessage;
using rclcpp::dynamic_typesupport::DynamicMessageType;
using rclcpp::dynamic_typesupport::DynamicSerializationSupport;
namespace
{
@@ -77,6 +82,18 @@ public:
const std::shared_ptr<rclcpp::SerializedMessage> &, const rclcpp::MessageInfo &) override {}
void return_message(std::shared_ptr<void> &) override {}
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> &) override {}
DynamicMessageType::SharedPtr get_shared_dynamic_message_type() override {return nullptr;}
DynamicMessage::SharedPtr get_shared_dynamic_message() override {return nullptr;}
DynamicSerializationSupport::SharedPtr get_shared_dynamic_serialization_support() override
{
return nullptr;
}
DynamicMessage::SharedPtr create_dynamic_message() override {return nullptr;}
void return_dynamic_message(DynamicMessage::SharedPtr &) override {}
void handle_dynamic_message(
const DynamicMessage::SharedPtr &,
const rclcpp::MessageInfo &) override {}
};
class TestNodeTopics : public ::testing::Test

View File

@@ -63,6 +63,57 @@ public:
}
};
static bool test_waitable_result2 = false;
class TestWaitable2 : public rclcpp::Waitable
{
public:
explicit TestWaitable2(rcl_publisher_t * pub_ptr)
: pub_ptr_(pub_ptr),
pub_event_(rcl_get_zero_initialized_event())
{
EXPECT_EQ(
rcl_publisher_event_init(&pub_event_, pub_ptr_, RCL_PUBLISHER_OFFERED_DEADLINE_MISSED),
RCL_RET_OK);
}
~TestWaitable2()
{
EXPECT_EQ(rcl_event_fini(&pub_event_), RCL_RET_OK);
}
void add_to_wait_set(rcl_wait_set_t * wait_set) override
{
EXPECT_EQ(rcl_wait_set_add_event(wait_set, &pub_event_, &wait_set_event_index_), RCL_RET_OK);
}
bool is_ready(rcl_wait_set_t *) override
{
return test_waitable_result2;
}
std::shared_ptr<void>
take_data() override
{
return nullptr;
}
void execute(std::shared_ptr<void> & data) override
{
(void) data;
}
size_t get_number_of_ready_events() override
{
return 1;
}
private:
rcl_publisher_t * pub_ptr_;
rcl_event_t pub_event_;
size_t wait_set_event_index_;
};
struct RclWaitSetSizes
{
size_t size_of_subscriptions = 0;
@@ -497,8 +548,8 @@ TEST_F(TestAllocatorMemoryStrategy, add_remove_waitables) {
TEST_F(TestAllocatorMemoryStrategy, number_of_entities_with_subscription) {
RclWaitSetSizes expected_sizes = {};
expected_sizes.size_of_subscriptions = 1;
expected_sizes.size_of_events = 1;
expected_sizes.size_of_waitables = 1;
expected_sizes.size_of_events = 2;
expected_sizes.size_of_waitables = 2;
auto node_with_subscription = create_node_with_subscription("subscription_node");
EXPECT_TRUE(TestNumberOfEntitiesAfterCollection(node_with_subscription, expected_sizes));
}
@@ -657,20 +708,129 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_timer) {
}
TEST_F(TestAllocatorMemoryStrategy, get_next_waitable) {
auto node1 = std::make_shared<rclcpp::Node>("waitable_node", "ns");
auto node2 = std::make_shared<rclcpp::Node>("waitable_node2", "ns");
rclcpp::Waitable::SharedPtr waitable1 = std::make_shared<TestWaitable>();
rclcpp::Waitable::SharedPtr waitable2 = std::make_shared<TestWaitable>();
node1->get_node_waitables_interface()->add_waitable(waitable1, nullptr);
node2->get_node_waitables_interface()->add_waitable(waitable2, nullptr);
auto get_next_entity = [this](const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) {
rclcpp::AnyExecutable result;
allocator_memory_strategy()->get_next_waitable(result, weak_groups_to_nodes);
return result;
};
EXPECT_TRUE(TestGetNextEntity(node1, node2, get_next_entity));
{
auto node1 = std::make_shared<rclcpp::Node>(
"waitable_node", "ns",
rclcpp::NodeOptions()
.start_parameter_event_publisher(false)
.start_parameter_services(false));
rclcpp::PublisherOptions pub_options;
pub_options.use_default_callbacks = false;
auto pub1 = node1->create_publisher<test_msgs::msg::Empty>(
"test_topic_1", rclcpp::QoS(10), pub_options);
auto waitable1 =
std::make_shared<TestWaitable2>(pub1->get_publisher_handle().get());
node1->get_node_waitables_interface()->add_waitable(waitable1, nullptr);
auto basic_node = create_node_with_disabled_callback_groups("basic_node");
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
basic_node->for_each_callback_group(
[basic_node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
basic_node->get_node_base_interface()));
});
node1->for_each_callback_group(
[node1, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
node1->get_node_base_interface()));
});
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
rcl_wait_set_t wait_set = rcl_get_zero_initialized_wait_set();
ASSERT_EQ(
rcl_wait_set_init(
&wait_set,
allocator_memory_strategy()->number_of_ready_subscriptions(),
allocator_memory_strategy()->number_of_guard_conditions(),
allocator_memory_strategy()->number_of_ready_timers(),
allocator_memory_strategy()->number_of_ready_clients(),
allocator_memory_strategy()->number_of_ready_services(),
allocator_memory_strategy()->number_of_ready_events(),
rclcpp::contexts::get_global_default_context()->get_rcl_context().get(),
allocator_memory_strategy()->get_allocator()),
RCL_RET_OK);
ASSERT_TRUE(allocator_memory_strategy()->add_handles_to_wait_set(&wait_set));
ASSERT_EQ(
rcl_wait(
&wait_set,
std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::milliseconds(100))
.count()),
RCL_RET_OK);
test_waitable_result2 = true;
allocator_memory_strategy()->remove_null_handles(&wait_set);
rclcpp::AnyExecutable result = get_next_entity(weak_groups_to_nodes);
EXPECT_EQ(result.node_base, node1->get_node_base_interface());
test_waitable_result2 = false;
EXPECT_EQ(rcl_wait_set_fini(&wait_set), RCL_RET_OK);
}
{
auto node2 = std::make_shared<rclcpp::Node>(
"waitable_node2", "ns",
rclcpp::NodeOptions()
.start_parameter_services(false)
.start_parameter_event_publisher(false));
rclcpp::PublisherOptions pub_options;
pub_options.use_default_callbacks = false;
auto pub2 = node2->create_publisher<test_msgs::msg::Empty>(
"test_topic_2", rclcpp::QoS(10), pub_options);
auto waitable2 =
std::make_shared<TestWaitable2>(pub2->get_publisher_handle().get());
node2->get_node_waitables_interface()->add_waitable(waitable2, nullptr);
auto basic_node2 = std::make_shared<rclcpp::Node>(
"basic_node2", "ns",
rclcpp::NodeOptions()
.start_parameter_services(false)
.start_parameter_event_publisher(false));
WeakCallbackGroupsToNodesMap weak_groups_to_uncollected_nodes;
basic_node2->for_each_callback_group(
[basic_node2, &weak_groups_to_uncollected_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
weak_groups_to_uncollected_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
basic_node2->get_node_base_interface()));
});
node2->for_each_callback_group(
[node2,
&weak_groups_to_uncollected_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
{
weak_groups_to_uncollected_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
group_ptr,
node2->get_node_base_interface()));
});
rclcpp::AnyExecutable failed_result = get_next_entity(weak_groups_to_uncollected_nodes);
EXPECT_EQ(failed_result.node_base, nullptr);
}
}
TEST_F(TestAllocatorMemoryStrategy, get_next_subscription_mutually_exclusive) {

View File

@@ -393,6 +393,7 @@ TEST(TestFunctionTraits, argument_types) {
auto bind_one_bool = std::bind(
&ObjectMember::callback_one_bool, &object_member, std::placeholders::_1);
(void)bind_one_bool; // to quiet clang
static_assert(
std::is_same<
@@ -402,6 +403,7 @@ TEST(TestFunctionTraits, argument_types) {
auto bind_one_bool_const = std::bind(
&ObjectMember::callback_one_bool_const, &object_member, std::placeholders::_1);
(void)bind_one_bool_const; // to quiet clang
static_assert(
std::is_same<
@@ -413,6 +415,7 @@ TEST(TestFunctionTraits, argument_types) {
auto bind_two_bools = std::bind(
&ObjectMember::callback_two_bools, &object_member, std::placeholders::_1,
std::placeholders::_2);
(void)bind_two_bools; // to quiet clang
static_assert(
std::is_same<
@@ -429,6 +432,7 @@ TEST(TestFunctionTraits, argument_types) {
auto bind_one_bool_one_float = std::bind(
&ObjectMember::callback_one_bool_one_float, &object_member, std::placeholders::_1,
std::placeholders::_2);
(void)bind_one_bool_one_float; // to quiet clang
static_assert(
std::is_same<
@@ -447,6 +451,7 @@ TEST(TestFunctionTraits, argument_types) {
>::value, "Functor accepts a float as second argument");
auto bind_one_int = std::bind(func_one_int, std::placeholders::_1);
(void)bind_one_int; // to quiet clang
static_assert(
std::is_same<
@@ -455,6 +460,7 @@ TEST(TestFunctionTraits, argument_types) {
>::value, "Functor accepts an int as first argument");
auto bind_two_ints = std::bind(func_two_ints, std::placeholders::_1, std::placeholders::_2);
(void)bind_two_ints; // to quiet clang
static_assert(
std::is_same<
@@ -470,6 +476,7 @@ TEST(TestFunctionTraits, argument_types) {
auto bind_one_int_one_char = std::bind(
func_one_int_one_char, std::placeholders::_1, std::placeholders::_2);
(void)bind_one_int_one_char; // to quiet clang
static_assert(
std::is_same<
@@ -530,18 +537,21 @@ TEST(TestFunctionTraits, check_arguments) {
(void)one;
return 1;
};
(void)lambda_one_int; // to quiet clang
auto lambda_two_ints = [](int one, int two) {
(void)one;
(void)two;
return 2;
};
(void)lambda_two_ints; // to quiet clang
auto lambda_one_int_one_char = [](int one, char two) {
(void)one;
(void)two;
return 3;
};
(void)lambda_one_int_one_char; // to quiet clang
static_assert(
rclcpp::function_traits::check_arguments<decltype(lambda_one_int), int>::value,
@@ -572,6 +582,7 @@ TEST(TestFunctionTraits, check_arguments) {
auto bind_one_bool = std::bind(
&ObjectMember::callback_one_bool, &object_member, std::placeholders::_1);
(void)bind_one_bool; // to quiet clang
// Test std::bind functions
static_assert(
@@ -580,6 +591,7 @@ TEST(TestFunctionTraits, check_arguments) {
auto bind_one_bool_const = std::bind(
&ObjectMember::callback_one_bool_const, &object_member, std::placeholders::_1);
(void)bind_one_bool_const; // to quiet clang
// Test std::bind functions
static_assert(
@@ -745,6 +757,7 @@ TEST_F(TestMember, bind_member_functor) {
auto bind_member_functor = std::bind(
&TestMember::MemberFunctor, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3);
(void)bind_member_functor; // to quiet clang
static_assert(
rclcpp::function_traits::check_arguments<decltype(bind_member_functor), int, float,

View File

@@ -89,9 +89,9 @@ public:
T2 message;
write_message(data, message);
rclcpp::Serialization<T2> ser;
rclcpp::Serialization<T2> serialization_support;
SerializedMessage result;
ser.serialize_message(&message, &result);
serialization_support.serialize_message(&message, &result);
return result;
}

View File

@@ -186,7 +186,6 @@ TEST_F(TestLoanedMessage, move_loaned_message) {
auto loaned_msg_moved_to = LoanedMessageT(std::move(loaned_msg_to_move));
ASSERT_TRUE(loaned_msg_moved_to.is_valid());
ASSERT_FALSE(loaned_msg_to_move.is_valid());
loaned_msg_moved_to.get().float32_value = 42.0f;
ASSERT_EQ(42.0f, loaned_msg_moved_to.get().float32_value);

View File

@@ -160,6 +160,50 @@ TEST(TestLogger, set_level) {
EXPECT_EQ(RCUTILS_RET_OK, rcutils_logging_shutdown());
}
TEST(TestLogger, get_effective_level) {
ASSERT_EQ(RCUTILS_RET_OK, rcutils_logging_initialize());
rclcpp::Logger logger = rclcpp::get_logger("test_logger");
rclcpp::Logger child_logger = rclcpp::get_logger("test_logger.child");
// set child logger level unset to test effective level
child_logger.set_level(rclcpp::Logger::Level::Unset);
// default
EXPECT_EQ(rclcpp::Logger::Level::Info, logger.get_effective_level());
EXPECT_EQ(rclcpp::Logger::Level::Info, child_logger.get_effective_level());
// unset
logger.set_level(rclcpp::Logger::Level::Unset);
EXPECT_EQ(rclcpp::Logger::Level::Info, logger.get_effective_level());
EXPECT_EQ(rclcpp::Logger::Level::Info, child_logger.get_effective_level());
// debug
logger.set_level(rclcpp::Logger::Level::Debug);
EXPECT_EQ(rclcpp::Logger::Level::Debug, logger.get_effective_level());
EXPECT_EQ(rclcpp::Logger::Level::Debug, child_logger.get_effective_level());
// info
logger.set_level(rclcpp::Logger::Level::Info);
EXPECT_EQ(rclcpp::Logger::Level::Info, logger.get_effective_level());
EXPECT_EQ(rclcpp::Logger::Level::Info, child_logger.get_effective_level());
// warn
logger.set_level(rclcpp::Logger::Level::Warn);
EXPECT_EQ(rclcpp::Logger::Level::Warn, logger.get_effective_level());
EXPECT_EQ(rclcpp::Logger::Level::Warn, child_logger.get_effective_level());
// error
logger.set_level(rclcpp::Logger::Level::Error);
EXPECT_EQ(rclcpp::Logger::Level::Error, logger.get_effective_level());
EXPECT_EQ(rclcpp::Logger::Level::Error, child_logger.get_effective_level());
// fatal
logger.set_level(rclcpp::Logger::Level::Fatal);
EXPECT_EQ(rclcpp::Logger::Level::Fatal, logger.get_effective_level());
EXPECT_EQ(rclcpp::Logger::Level::Fatal, child_logger.get_effective_level());
}
TEST(TestLogger, get_logging_directory) {
ASSERT_EQ(true, rcutils_set_env("HOME", "/fake_home_dir"));
ASSERT_EQ(true, rcutils_set_env("USERPROFILE", nullptr));

View File

@@ -409,9 +409,7 @@ TEST_F(TestPublisher, intra_process_publish_failures) {
std::allocator<void> allocator;
{
rclcpp::LoanedMessage<test_msgs::msg::Empty> loaned_msg(*publisher, allocator);
RCLCPP_EXPECT_THROW_EQ(
publisher->publish(std::move(loaned_msg)),
std::runtime_error("storing loaned messages in intra process is not supported yet"));
EXPECT_NO_THROW(publisher->publish(std::move(loaned_msg)));
}
{

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <atomic>
#include <chrono>
#include <functional>
#include <future>
@@ -232,7 +233,7 @@ TEST_F(TestQosEvent, construct_destruct_rcl_error) {
auto throwing_statement = [callback, rcl_handle, event_type]() {
// reset() is not needed for the exception, but it handles unused return value warning
std::make_shared<
rclcpp::QOSEventHandler<decltype(callback), std::shared_ptr<rcl_publisher_t>>>(
rclcpp::EventHandler<decltype(callback), std::shared_ptr<rcl_publisher_t>>>(
callback, rcl_publisher_event_init, rcl_handle, event_type).reset();
};
// This is done through a lambda because the compiler is having trouble parsing the templated
@@ -248,7 +249,7 @@ TEST_F(TestQosEvent, construct_destruct_rcl_error) {
auto throwing_statement = [callback, rcl_handle, event_type]() {
// reset() is needed for this exception
std::make_shared<
rclcpp::QOSEventHandler<decltype(callback), std::shared_ptr<rcl_publisher_t>>>(
rclcpp::EventHandler<decltype(callback), std::shared_ptr<rcl_publisher_t>>>(
callback, rcl_publisher_event_init, rcl_handle, event_type).reset();
};
@@ -267,7 +268,7 @@ TEST_F(TestQosEvent, execute) {
auto callback = [&handler_callback_executed](int) {handler_callback_executed = true;};
rcl_publisher_event_type_t event_type = RCL_PUBLISHER_OFFERED_DEADLINE_MISSED;
rclcpp::QOSEventHandler<decltype(callback), decltype(rcl_handle)> handler(
rclcpp::EventHandler<decltype(callback), decltype(rcl_handle)> handler(
callback, rcl_publisher_event_init, rcl_handle, event_type);
std::shared_ptr<void> data = handler.take_data();
@@ -292,7 +293,7 @@ TEST_F(TestQosEvent, add_to_wait_set) {
auto callback = [](int) {};
rcl_publisher_event_type_t event_type = RCL_PUBLISHER_OFFERED_DEADLINE_MISSED;
rclcpp::QOSEventHandler<decltype(callback), decltype(rcl_handle)> handler(
rclcpp::EventHandler<decltype(callback), decltype(rcl_handle)> handler(
callback, rcl_publisher_event_init, rcl_handle, event_type);
EXPECT_EQ(1u, handler.get_number_of_ready_events());
@@ -313,6 +314,11 @@ TEST_F(TestQosEvent, add_to_wait_set) {
TEST_F(TestQosEvent, test_on_new_event_callback)
{
// rmw_connextdds doesn't support rmw_event_set_callback() interface
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto offered_deadline = rclcpp::Duration(std::chrono::milliseconds(1));
auto requested_deadline = rclcpp::Duration(std::chrono::milliseconds(2));
@@ -354,6 +360,11 @@ TEST_F(TestQosEvent, test_on_new_event_callback)
TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
{
// rmw_connextdds doesn't support rmw_event_set_callback() interface
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
auto pub = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
auto sub = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
auto dummy_cb = [](size_t count_events) {(void)count_events;};
@@ -376,6 +387,12 @@ TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
EXPECT_NO_THROW(
pub->clear_on_new_qos_event_callback(RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS));
EXPECT_NO_THROW(
pub->set_on_new_qos_event_callback(dummy_cb, RCL_PUBLISHER_MATCHED));
EXPECT_NO_THROW(
pub->clear_on_new_qos_event_callback(RCL_PUBLISHER_MATCHED));
EXPECT_NO_THROW(
sub->set_on_new_qos_event_callback(dummy_cb, RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED));
@@ -394,6 +411,12 @@ TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
EXPECT_NO_THROW(
sub->clear_on_new_qos_event_callback(RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS));
EXPECT_NO_THROW(
sub->set_on_new_qos_event_callback(dummy_cb, RCL_SUBSCRIPTION_MATCHED));
EXPECT_NO_THROW(
sub->clear_on_new_qos_event_callback(RCL_SUBSCRIPTION_MATCHED));
std::function<void(size_t)> invalid_cb;
rclcpp::SubscriptionOptions sub_options;
@@ -413,3 +436,170 @@ TEST_F(TestQosEvent, test_invalid_on_new_event_callback)
pub->set_on_new_qos_event_callback(invalid_cb, RCL_PUBLISHER_OFFERED_DEADLINE_MISSED),
std::invalid_argument);
}
TEST_F(TestQosEvent, test_pub_matched_event_by_set_event_callback)
{
// rmw_connextdds doesn't support rmw_event_set_callback() interface
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
std::atomic_size_t matched_count = 0;
rclcpp::PublisherOptions pub_options;
pub_options.event_callbacks.matched_callback = [](auto) {};
auto pub = node->create_publisher<test_msgs::msg::Empty>(
topic_name, 10, pub_options);
auto matched_event_callback = [&matched_count](size_t count) {
matched_count += count;
};
pub->set_on_new_qos_event_callback(matched_event_callback, RCL_PUBLISHER_MATCHED);
rclcpp::executors::SingleThreadedExecutor ex;
ex.add_node(node->get_node_base_interface());
const auto timeout = std::chrono::milliseconds(200);
{
auto sub1 = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
ex.spin_some(timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(1));
{
auto sub2 = node->create_subscription<test_msgs::msg::Empty>(
topic_name, 10, message_callback);
ex.spin_some(timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(2));
}
ex.spin_some(timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(3));
}
ex.spin_some(timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(4));
}
TEST_F(TestQosEvent, test_sub_matched_event_by_set_event_callback)
{
// rmw_connextdds doesn't support rmw_event_set_callback() interface
if (std::string(rmw_get_implementation_identifier()).find("rmw_connextdds") == 0) {
GTEST_SKIP();
}
std::atomic_size_t matched_count = 0;
rclcpp::SubscriptionOptions sub_options;
sub_options.event_callbacks.matched_callback = [](auto) {};
auto sub = node->create_subscription<test_msgs::msg::Empty>(
topic_name, 10, message_callback, sub_options);
auto matched_event_callback = [&matched_count](size_t count) {
matched_count += count;
};
sub->set_on_new_qos_event_callback(matched_event_callback, RCL_SUBSCRIPTION_MATCHED);
rclcpp::executors::SingleThreadedExecutor ex;
ex.add_node(node->get_node_base_interface());
const auto timeout = std::chrono::milliseconds(200);
{
auto pub1 = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
ex.spin_some(timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(1));
{
auto pub2 = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
ex.spin_some(timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(2));
}
ex.spin_some(timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(3));
}
ex.spin_some(timeout);
EXPECT_EQ(matched_count, static_cast<size_t>(4));
}
TEST_F(TestQosEvent, test_pub_matched_event_by_option_event_callback)
{
rmw_matched_status_t matched_expected_result;
rclcpp::PublisherOptions pub_options;
pub_options.event_callbacks.matched_callback =
[&matched_expected_result](rmw_matched_status_t & s) {
EXPECT_EQ(s.total_count, matched_expected_result.total_count);
EXPECT_EQ(s.total_count_change, matched_expected_result.total_count_change);
EXPECT_EQ(s.current_count, matched_expected_result.current_count);
EXPECT_EQ(s.current_count_change, matched_expected_result.current_count_change);
};
auto pub = node->create_publisher<test_msgs::msg::Empty>(
topic_name, 10, pub_options);
rclcpp::executors::SingleThreadedExecutor ex;
ex.add_node(node->get_node_base_interface());
// Create a connected subscription
matched_expected_result.total_count = 1;
matched_expected_result.total_count_change = 1;
matched_expected_result.current_count = 1;
matched_expected_result.current_count_change = 1;
const auto timeout = std::chrono::milliseconds(200);
{
auto sub = node->create_subscription<test_msgs::msg::Empty>(topic_name, 10, message_callback);
ex.spin_some(timeout);
// destroy a connected subscription
matched_expected_result.total_count = 1;
matched_expected_result.total_count_change = 0;
matched_expected_result.current_count = 0;
matched_expected_result.current_count_change = -1;
}
ex.spin_some(timeout);
}
TEST_F(TestQosEvent, test_sub_matched_event_by_option_event_callback)
{
rmw_matched_status_t matched_expected_result;
rclcpp::SubscriptionOptions sub_options;
sub_options.event_callbacks.matched_callback =
[&matched_expected_result](rmw_matched_status_t & s) {
EXPECT_EQ(s.total_count, matched_expected_result.total_count);
EXPECT_EQ(s.total_count_change, matched_expected_result.total_count_change);
EXPECT_EQ(s.current_count, matched_expected_result.current_count);
EXPECT_EQ(s.current_count_change, matched_expected_result.current_count_change);
};
auto sub = node->create_subscription<test_msgs::msg::Empty>(
topic_name, 10, message_callback, sub_options);
rclcpp::executors::SingleThreadedExecutor ex;
ex.add_node(node->get_node_base_interface());
// Create a connected publisher
matched_expected_result.total_count = 1;
matched_expected_result.total_count_change = 1;
matched_expected_result.current_count = 1;
matched_expected_result.current_count_change = 1;
const auto timeout = std::chrono::milliseconds(200);
{
auto pub1 = node->create_publisher<test_msgs::msg::Empty>(topic_name, 10);
ex.spin_some(timeout);
// destroy a connected publisher
matched_expected_result.total_count = 1;
matched_expected_result.total_count_change = 0;
matched_expected_result.current_count = 0;
matched_expected_result.current_count_change = -1;
}
ex.spin_some(timeout);
}

View File

@@ -0,0 +1,180 @@
// Copyright 2021 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 <memory>
#include <string>
#include "rclcpp/rclcpp.hpp"
#include "rcl_interfaces/msg/log.hpp"
using namespace std::chrono_literals;
class TestRosoutSubscription : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>("test_rosout_subscription", "/ns");
sub = node->create_subscription<rcl_interfaces::msg::Log>(
"/rosout", 10, [this](rcl_interfaces::msg::Log::ConstSharedPtr msg) {
if (msg->msg == this->rosout_msg_data &&
msg->name == this->rosout_msg_name)
{
received_msg_promise.set_value(true);
}
});
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
rclcpp::Subscription<rcl_interfaces::msg::Log>::SharedPtr sub;
std::promise<bool> received_msg_promise;
std::string rosout_msg_data;
std::string rosout_msg_name;
};
TEST_F(TestRosoutSubscription, test_rosoutsubscription_getchild) {
std::string logger_name = "ns.test_rosout_subscription.child";
this->rosout_msg_data = "SOMETHING";
this->rosout_msg_name = logger_name;
{
// before calling get_child of Logger
{
RCLCPP_INFO(
rclcpp::get_logger(logger_name), this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::TIMEOUT, return_code);
received_msg_promise = {};
}
rclcpp::Logger child_logger = this->node->get_logger().get_child("child");
ASSERT_EQ(child_logger.get_name(), logger_name);
// after calling get_child of Logger
// 1. use child_logger directly
{
RCLCPP_INFO(child_logger, this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
EXPECT_TRUE(future.get());
received_msg_promise = {};
}
// 2. use rclcpp::get_logger
{
RCLCPP_INFO(rclcpp::get_logger(logger_name), this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
EXPECT_TRUE(future.get());
received_msg_promise = {};
}
}
// `child_logger` is end of life, there is no sublogger
{
RCLCPP_INFO(rclcpp::get_logger(logger_name), this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::TIMEOUT, return_code);
received_msg_promise = {};
}
}
TEST_F(TestRosoutSubscription, test_rosoutsubscription_parent_log) {
std::string logger_name = "ns.test_rosout_subscription";
this->rosout_msg_data = "SOMETHING";
this->rosout_msg_name = logger_name;
rclcpp::Logger logger = this->node->get_logger();
ASSERT_EQ(logger.get_name(), logger_name);
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
EXPECT_TRUE(future.get());
received_msg_promise = {};
}
TEST_F(TestRosoutSubscription, test_rosoutsubscription_child_log) {
std::string logger_name = "ns.test_rosout_subscription.child1";
this->rosout_msg_data = "SOMETHING";
this->rosout_msg_name = logger_name;
rclcpp::Logger logger = this->node->get_logger();
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::TIMEOUT, return_code);
received_msg_promise = {};
logger = this->node->get_logger().get_child("child1");
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
future = received_msg_promise.get_future();
return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
EXPECT_TRUE(future.get());
received_msg_promise = {};
logger = this->node->get_logger().get_child("child2");
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
future = received_msg_promise.get_future();
return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::TIMEOUT, return_code);
received_msg_promise = {};
this->rosout_msg_name = "ns.test_rosout_subscription.child2";
RCLCPP_INFO(logger, this->rosout_msg_data.c_str());
future = received_msg_promise.get_future();
return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
EXPECT_TRUE(future.get());
received_msg_promise = {};
}
TEST_F(TestRosoutSubscription, test_rosoutsubscription_getchild_hierarchy) {
std::string logger_name = "ns.test_rosout_subscription.child.grandchild";
this->rosout_msg_data = "SOMETHING";
this->rosout_msg_name = logger_name;
rclcpp::Logger grandchild_logger =
this->node->get_logger().get_child("child").get_child("grandchild");
ASSERT_EQ(grandchild_logger.get_name(), logger_name);
RCLCPP_INFO(grandchild_logger, this->rosout_msg_data.c_str());
auto future = received_msg_promise.get_future();
auto return_code = rclcpp::spin_until_future_complete(this->node, future, 3s);
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
EXPECT_TRUE(future.get());
received_msg_promise = {};
}

View File

@@ -67,8 +67,6 @@ TEST(TestSerializedMessage, various_constructors) {
rclcpp::SerializedMessage yet_another_serialized_message(std::move(other_serialized_message));
auto & yet_another_rcl_handle = yet_another_serialized_message.get_rcl_serialized_message();
EXPECT_TRUE(nullptr == other_rcl_handle.buffer);
EXPECT_EQ(0u, other_serialized_message.capacity());
EXPECT_EQ(0u, other_serialized_message.size());
EXPECT_TRUE(nullptr != yet_another_rcl_handle.buffer);
EXPECT_EQ(content_size, yet_another_serialized_message.size());
EXPECT_EQ(content_size, yet_another_serialized_message.capacity());

View File

@@ -0,0 +1,339 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <rcl/service_introspection.h>
#include <rmw/rmw.h>
#include <map>
#include <string>
#include "gmock/gmock.h"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/node_options.hpp"
#include "rclcpp/parameter.hpp"
#include "../mocking_utils/patch.hpp"
#include "../utils/rclcpp_gtest_macros.hpp"
#include "test_msgs/srv/basic_types.hpp"
#include "service_msgs/msg/service_event_info.hpp"
using namespace std::chrono_literals;
using test_msgs::srv::BasicTypes;
using service_msgs::msg::ServiceEventInfo;
class TestServiceIntrospection : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node = std::make_shared<rclcpp::Node>(
"my_node", "/ns");
auto srv_callback =
[](const BasicTypes::Request::SharedPtr & req, const BasicTypes::Response::SharedPtr & resp) {
resp->set__bool_value(!req->bool_value);
resp->set__int64_value(req->int64_value);
return resp;
};
auto callback = [this](const std::shared_ptr<const BasicTypes::Event> & msg) {
events.push_back(msg);
(void)msg;
};
client = node->create_client<BasicTypes>("service");
service = node->create_service<BasicTypes>("service", srv_callback);
sub = node->create_subscription<BasicTypes::Event>("service/_service_event", 10, callback);
events.clear();
}
void TearDown()
{
node.reset();
}
rclcpp::Node::SharedPtr node;
rclcpp::Client<BasicTypes>::SharedPtr client;
rclcpp::Service<BasicTypes>::SharedPtr service;
rclcpp::Subscription<BasicTypes::Event>::SharedPtr sub;
std::vector<std::shared_ptr<const BasicTypes::Event>> events;
std::chrono::milliseconds timeout = std::chrono::milliseconds(1000);
};
TEST_F(TestServiceIntrospection, service_introspection_nominal)
{
auto request = std::make_shared<BasicTypes::Request>();
request->set__bool_value(true);
request->set__int64_value(42);
client->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
service->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
auto future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
rclcpp::spin_until_future_complete(node, future, timeout));
BasicTypes::Response::SharedPtr response = future.get();
ASSERT_EQ(response->bool_value, false);
ASSERT_EQ(response->int64_value, 42);
// 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) {
rclcpp::spin_some(node);
}
std::map<uint8_t, std::shared_ptr<const BasicTypes::Event>> event_map;
for (auto & event : events) {
event_map[event->info.event_type] = event;
}
ASSERT_EQ(event_map.size(), 4U);
rmw_gid_t client_gid;
rmw_get_gid_for_client(rcl_client_get_rmw_handle(client->get_client_handle().get()), &client_gid);
std::array<uint8_t, RMW_GID_STORAGE_SIZE> client_gid_arr;
std::move(std::begin(client_gid.data), std::end(client_gid.data), client_gid_arr.begin());
ASSERT_THAT(
client_gid_arr,
testing::Eq(event_map[ServiceEventInfo::REQUEST_SENT]->info.client_gid));
ASSERT_EQ(
event_map[ServiceEventInfo::REQUEST_SENT]->info.sequence_number,
event_map[ServiceEventInfo::REQUEST_RECEIVED]->info.sequence_number);
ASSERT_EQ(
event_map[ServiceEventInfo::RESPONSE_SENT]->info.sequence_number,
event_map[ServiceEventInfo::RESPONSE_RECEIVED]->info.sequence_number);
ASSERT_EQ(
event_map[ServiceEventInfo::REQUEST_SENT]->info.sequence_number,
event_map[ServiceEventInfo::RESPONSE_SENT]->info.sequence_number);
ASSERT_EQ(
event_map[ServiceEventInfo::REQUEST_RECEIVED]->info.sequence_number,
event_map[ServiceEventInfo::RESPONSE_RECEIVED]->info.sequence_number);
ASSERT_EQ(event_map[ServiceEventInfo::REQUEST_SENT]->request[0].int64_value, 42);
ASSERT_EQ(event_map[ServiceEventInfo::REQUEST_SENT]->request[0].bool_value, true);
ASSERT_EQ(event_map[ServiceEventInfo::RESPONSE_SENT]->response[0].int64_value, 42);
ASSERT_EQ(event_map[ServiceEventInfo::RESPONSE_SENT]->response[0].bool_value, false);
ASSERT_EQ(event_map[ServiceEventInfo::RESPONSE_SENT]->request.size(), 0U);
ASSERT_EQ(event_map[ServiceEventInfo::REQUEST_RECEIVED]->response.size(), 0U);
}
TEST_F(TestServiceIntrospection, service_introspection_enable_disable_events)
{
client->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_OFF);
service->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_OFF);
auto request = std::make_shared<BasicTypes::Request>();
request->set__bool_value(true);
request->set__int64_value(42);
auto future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
rclcpp::spin_until_future_complete(node, future, timeout));
auto start = std::chrono::steady_clock::now();
while ((std::chrono::steady_clock::now() - start) < timeout) {
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 0U);
events.clear();
client->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
service->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_OFF);
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
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) {
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 2U);
events.clear();
client->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_OFF);
service->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
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) {
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 2U);
events.clear();
client->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
service->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
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) {
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
}
TEST_F(TestServiceIntrospection, service_introspection_enable_disable_event_content)
{
client->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
service->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
auto request = std::make_shared<BasicTypes::Request>();
request->set__bool_value(true);
request->set__int64_value(42);
auto future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
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) {
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
for (const auto & event : events) {
EXPECT_EQ(event->request.size(), 0U);
EXPECT_EQ(event->response.size(), 0U);
}
events.clear();
client->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
service->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
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) {
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
for (const auto & event : events) {
switch (event->info.event_type) {
case ServiceEventInfo::REQUEST_SENT:
EXPECT_EQ(event->request.size(), 1U);
break;
case ServiceEventInfo::REQUEST_RECEIVED:
EXPECT_EQ(event->request.size(), 0U);
break;
case ServiceEventInfo::RESPONSE_SENT:
EXPECT_EQ(event->response.size(), 0U);
break;
case ServiceEventInfo::RESPONSE_RECEIVED:
EXPECT_EQ(event->response.size(), 1U);
break;
}
}
events.clear();
client->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_METADATA);
service->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
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) {
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
for (const auto & event : events) {
switch (event->info.event_type) {
case ServiceEventInfo::REQUEST_SENT:
EXPECT_EQ(event->request.size(), 0U);
break;
case ServiceEventInfo::REQUEST_RECEIVED:
EXPECT_EQ(event->request.size(), 1U);
break;
case ServiceEventInfo::RESPONSE_SENT:
EXPECT_EQ(event->response.size(), 1U);
break;
case ServiceEventInfo::RESPONSE_RECEIVED:
EXPECT_EQ(event->response.size(), 0U);
break;
}
}
events.clear();
client->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
service->configure_introspection(
node->get_clock(), rclcpp::SystemDefaultsQoS(), RCL_SERVICE_INTROSPECTION_CONTENTS);
future = client->async_send_request(request);
ASSERT_EQ(
rclcpp::FutureReturnCode::SUCCESS,
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) {
rclcpp::spin_some(node);
}
EXPECT_EQ(events.size(), 4U);
for (const auto & event : events) {
switch (event->info.event_type) {
case ServiceEventInfo::REQUEST_SENT:
case ServiceEventInfo::REQUEST_RECEIVED:
EXPECT_EQ(event->request.size(), 1U);
break;
case ServiceEventInfo::RESPONSE_SENT:
case ServiceEventInfo::RESPONSE_RECEIVED:
EXPECT_EQ(event->response.size(), 1U);
break;
}
}
}

View File

@@ -81,7 +81,7 @@ void spin_until_time(
executor.spin_once(10ms);
if (clock->now().nanoseconds() >= end_time.count()) {
if (clock->now().nanoseconds() == end_time.count()) {
return;
}
}

View File

@@ -3,6 +3,12 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19.3.0 (2023-03-01)
-------------------
19.2.0 (2023-02-24)
-------------------
19.1.0 (2023-02-14)
-------------------

View File

@@ -9,9 +9,10 @@ find_package(rcl_action REQUIRED)
find_package(rcpputils REQUIRED)
find_package(rosidl_runtime_c REQUIRED)
# Default to C++14
# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(

View File

@@ -34,7 +34,7 @@ using GoalUUID = std::array<uint8_t, UUID_SIZE>;
using GoalStatus = action_msgs::msg::GoalStatus;
using GoalInfo = action_msgs::msg::GoalInfo;
/// Convert a goal id to a human readable string.
/// Convert a goal id to a human readable RFC-4122 compliant string.
RCLCPP_ACTION_PUBLIC
std::string
to_string(const GoalUUID & goal_id);

View File

@@ -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>19.1.0</version>
<version>19.3.0</version>
<description>Adds action APIs for C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -318,14 +318,19 @@ ClientBase::handle_result_response(
const rmw_request_id_t & response_header,
std::shared_ptr<void> response)
{
std::lock_guard<std::mutex> guard(pimpl_->result_requests_mutex);
const int64_t & sequence_number = response_header.sequence_number;
if (pimpl_->pending_result_responses.count(sequence_number) == 0) {
RCLCPP_ERROR(pimpl_->logger, "unknown result response, ignoring...");
return;
std::map<int64_t, ResponseCallback>::node_type pending_result_response;
{
std::lock_guard<std::mutex> guard(pimpl_->result_requests_mutex);
const int64_t & sequence_number = response_header.sequence_number;
if (pimpl_->pending_result_responses.count(sequence_number) == 0) {
RCLCPP_ERROR(pimpl_->logger, "unknown result response, ignoring...");
return;
}
pending_result_response =
pimpl_->pending_result_responses.extract(sequence_number);
}
pimpl_->pending_result_responses[sequence_number](response);
pimpl_->pending_result_responses.erase(sequence_number);
auto & response_callback = pending_result_response.mapped();
response_callback(response);
}
void

View File

@@ -15,25 +15,33 @@
#include "rclcpp_action/types.hpp"
#include <string>
#include <sstream>
namespace rclcpp_action
{
std::string
to_string(const GoalUUID & goal_id)
{
std::stringstream stream;
stream << std::hex;
for (const auto & element : goal_id) {
stream << static_cast<int>(element);
constexpr char HEX[] = "0123456789abcdef";
std::string result;
result.resize(36);
size_t i = 0;
for (uint8_t byte : goal_id) {
result[i++] = HEX[byte >> 4];
result[i++] = HEX[byte & 0x0f];
// A RFC-4122 compliant UUID looks like:
// 00000000-0000-0000-0000-000000000000
// That means that there is a '-' at offset 8, 13, 18, and 23
if (i == 8 || i == 13 || i == 18 || i == 23) {
result[i++] = '-';
}
}
return stream.str();
return result;
}
void
convert(const GoalUUID & goal_id, rcl_action_goal_info_t * info)
{
for (size_t i = 0; i < 16; ++i) {
for (size_t i = 0; i < UUID_SIZE; ++i) {
info->goal_id.uuid[i] = goal_id[i];
}
}
@@ -41,7 +49,7 @@ convert(const GoalUUID & goal_id, rcl_action_goal_info_t * info)
void
convert(const rcl_action_goal_info_t & info, GoalUUID * goal_id)
{
for (size_t i = 0; i < 16; ++i) {
for (size_t i = 0; i < UUID_SIZE; ++i) {
(*goal_id)[i] = info.goal_id.uuid[i];
}
}

View File

@@ -22,17 +22,17 @@ TEST(TestActionTypes, goal_uuid_to_string) {
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
goal_id[i] = i;
}
EXPECT_STREQ("0123456789abcdef", rclcpp_action::to_string(goal_id).c_str());
EXPECT_STREQ("00010203-0405-0607-0809-0a0b0c0d0e0f", rclcpp_action::to_string(goal_id).c_str());
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
goal_id[i] = static_cast<uint8_t>(16u + i);
}
EXPECT_STREQ("101112131415161718191a1b1c1d1e1f", rclcpp_action::to_string(goal_id).c_str());
EXPECT_STREQ("10111213-1415-1617-1819-1a1b1c1d1e1f", rclcpp_action::to_string(goal_id).c_str());
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
goal_id[i] = static_cast<uint8_t>(std::numeric_limits<uint8_t>::max() - i);
}
EXPECT_STREQ("fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0", rclcpp_action::to_string(goal_id).c_str());
EXPECT_STREQ("fffefdfc-fbfa-f9f8-f7f6-f5f4f3f2f1f0", rclcpp_action::to_string(goal_id).c_str());
}
TEST(TestActionTypes, goal_uuid_to_rcl_action_goal_info) {
@@ -54,7 +54,7 @@ TEST(TestActionTypes, rcl_action_goal_info_to_goal_uuid) {
}
rclcpp_action::GoalUUID goal_id;
rclcpp_action::convert(goal_id, &goal_info);
rclcpp_action::convert(goal_info, &goal_id);
for (uint8_t i = 0; i < UUID_SIZE; ++i) {
EXPECT_EQ(goal_info.goal_id.uuid[i], goal_id[i]);
}

View File

@@ -2,6 +2,12 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19.3.0 (2023-03-01)
-------------------
19.2.0 (2023-02-24)
-------------------
19.1.0 (2023-02-14)
-------------------

View File

@@ -2,9 +2,10 @@ cmake_minimum_required(VERSION 3.5)
project(rclcpp_components)
# Default to C++14
# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(

View File

@@ -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_components</name>
<version>19.1.0</version>
<version>19.3.0</version>
<description>Package containing tools for dynamically loadable components</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -3,6 +3,12 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
19.3.0 (2023-03-01)
-------------------
19.2.0 (2023-02-24)
-------------------
19.1.0 (2023-02-14)
-------------------

View File

@@ -2,9 +2,10 @@ cmake_minimum_required(VERSION 3.5)
project(rclcpp_lifecycle)
# Default to C++14
# Default to C++17
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic -Wnon-virtual-dtor -Woverloaded-virtual)

View File

@@ -172,6 +172,15 @@ public:
const char *
get_namespace() const;
/// Get the fully-qualified name of the node.
/**
* The fully-qualified name includes the local namespace and name of the node.
* \return fully-qualified name of the node.
*/
RCLCPP_LIFECYCLE_PUBLIC
const char *
get_fully_qualified_name() const;
/// Get the logger of the node.
/**
* \return The logger of the node.

View File

@@ -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_lifecycle</name>
<version>19.1.0</version>
<version>19.3.0</version>
<description>Package containing a prototype for lifecycle implementation</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>

View File

@@ -165,6 +165,12 @@ LifecycleNode::get_namespace() const
return node_base_->get_namespace();
}
const char *
LifecycleNode::get_fully_qualified_name() const
{
return node_base_->get_fully_qualified_name();
}
rclcpp::Logger
LifecycleNode::get_logger() const
{

View File

@@ -229,6 +229,7 @@ TEST_F(TestDefaultStateMachine, empty_initializer) {
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
EXPECT_STREQ("testnode", test_node->get_name());
EXPECT_STREQ("/", test_node->get_namespace());
EXPECT_STREQ("/testnode", test_node->get_fully_qualified_name());
EXPECT_EQ(State::PRIMARY_STATE_UNCONFIGURED, test_node->get_current_state().id());
}

View File

@@ -133,6 +133,7 @@ TEST_P(TestLifecyclePublisher, publish_managed_by_node) {
rclcpp_lifecycle::Transition(Transition::TRANSITION_DEACTIVATE), ret);
ASSERT_EQ(success, ret);
ret = reset_key;
(void)ret; // Just to make clang happy
EXPECT_FALSE(node_->publisher()->is_activated());
{
auto msg_ptr = std::make_unique<test_msgs::msg::Empty>();