15 #ifndef RCLCPP__SUBSCRIPTION_HPP_
16 #define RCLCPP__SUBSCRIPTION_HPP_
18 #include <rmw/error_handling.h>
27 #include "rcl/error_handling.h"
30 #include "rclcpp/any_subscription_callback.hpp"
31 #include "rclcpp/detail/resolve_use_intra_process.hpp"
32 #include "rclcpp/detail/resolve_intra_process_buffer_type.hpp"
33 #include "rclcpp/exceptions.hpp"
34 #include "rclcpp/expand_topic_or_service_name.hpp"
35 #include "rclcpp/experimental/intra_process_manager.hpp"
36 #include "rclcpp/experimental/subscription_intra_process.hpp"
37 #include "rclcpp/logging.hpp"
38 #include "rclcpp/macros.hpp"
39 #include "rclcpp/message_info.hpp"
40 #include "rclcpp/message_memory_strategy.hpp"
41 #include "rclcpp/node_interfaces/node_base_interface.hpp"
42 #include "rclcpp/subscription_base.hpp"
43 #include "rclcpp/subscription_options.hpp"
44 #include "rclcpp/type_support_decl.hpp"
45 #include "rclcpp/visibility_control.hpp"
46 #include "rclcpp/waitable.hpp"
47 #include "rclcpp/topic_statistics/subscription_topic_statistics.hpp"
48 #include "tracetools/tracetools.h"
53 namespace node_interfaces
55 class NodeTopicsInterface;
61 typename AllocatorT = std::allocator<void>,
64 typename SubscribedT =
typename rclcpp::TypeAdapter<MessageT>::custom_type,
67 typename ROSMessageT =
typename rclcpp::TypeAdapter<MessageT>::ros_message_type,
78 using SubscribedType = SubscribedT;
79 using ROSMessageType = ROSMessageT;
80 using MessageMemoryStrategyType = MessageMemoryStrategyT;
82 using SubscribedTypeAllocatorTraits = allocator::AllocRebind<SubscribedType, AllocatorT>;
83 using SubscribedTypeAllocator =
typename SubscribedTypeAllocatorTraits::allocator_type;
84 using SubscribedTypeDeleter = allocator::Deleter<SubscribedTypeAllocator, SubscribedType>;
86 using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
87 using ROSMessageTypeAllocator =
typename ROSMessageTypeAllocatorTraits::allocator_type;
88 using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
91 using SubscriptionTopicStatisticsSharedPtr =
92 std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>;
117 rclcpp::node_interfaces::NodeBaseInterface * node_base,
118 const rosidl_message_type_support_t & type_support_handle,
119 const std::
string & topic_name,
123 typename MessageMemoryStrategyT::SharedPtr message_memory_strategy,
124 SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics =
nullptr)
129 options.to_rcl_subscription_options(qos),
131 options.event_callbacks,
132 options.use_default_callbacks,
134 any_callback_(callback),
136 message_memory_strategy_(message_memory_strategy)
140 if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
141 using rclcpp::detail::resolve_intra_process_buffer_type;
145 if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
146 throw std::invalid_argument(
147 "intraprocess communication on topic '" + topic_name +
148 "' allowed only with keep last history qos policy");
150 if (qos_profile.depth() == 0) {
151 throw std::invalid_argument(
152 "intraprocess communication on topic '" + topic_name +
153 "' is not allowed with 0 depth qos policy");
159 SubscribedTypeAllocator,
160 SubscribedTypeDeleter,
166 typename SubscriptionIntraProcessT::StatsHandlerFn stats_handler =
nullptr;
167 if (subscription_topic_statistics) {
169 [subscription_topic_statistics](
170 const rmw_message_info_t & info,
const rclcpp::Time & time)
172 subscription_topic_statistics->handle_message(info, time);
177 auto context = node_base->get_context();
178 subscription_intra_process_ = std::make_shared<SubscriptionIntraProcessT>(
180 options_.get_allocator(),
182 this->get_topic_name(),
184 resolve_intra_process_buffer_type(options_.intra_process_buffer_type, callback),
185 std::move(stats_handler));
186 TRACETOOLS_TRACEPOINT(
187 rclcpp_subscription_init,
188 static_cast<const void *
>(get_subscription_handle().get()),
189 static_cast<const void *
>(subscription_intra_process_.get()));
193 auto ipm = context->get_sub_context<IntraProcessManager>();
194 uint64_t intra_process_subscription_id = ipm->template add_subscription<
195 ROSMessageType, ROSMessageTypeAllocator>(subscription_intra_process_);
199 if (subscription_topic_statistics !=
nullptr) {
200 this->subscription_topic_statistics_ = std::move(subscription_topic_statistics);
203 TRACETOOLS_TRACEPOINT(
204 rclcpp_subscription_init,
205 static_cast<const void *
>(get_subscription_handle().get()),
206 static_cast<const void *
>(
this));
207 TRACETOOLS_TRACEPOINT(
208 rclcpp_subscription_callback_added,
209 static_cast<const void *
>(
this),
210 static_cast<const void *
>(&any_callback_));
214 #ifndef TRACETOOLS_DISABLED
215 any_callback_.register_callback_for_tracing();
250 return this->
take_type_erased(
static_cast<void *
>(&message_out), message_info_out);
260 template<
typename TakeT>
262 !rosidl_generator_traits::is_message<TakeT>::value &&
263 std::is_same_v<TakeT, SubscribedType>,
268 ROSMessageType local_message;
269 bool taken = this->
take_type_erased(
static_cast<void *
>(&local_message), message_info_out);
276 std::shared_ptr<void>
283 return message_memory_strategy_->borrow_message();
286 std::shared_ptr<rclcpp::SerializedMessage>
289 return message_memory_strategy_->borrow_serialized_message();
305 any_callback_.disable();
306 if (subscription_intra_process_) {
307 subscription_intra_process_->disable_callbacks();
309 for (
const auto & [_, event_ptr] : event_handlers_) {
311 event_ptr->disable();
325 any_callback_.enable();
326 if (subscription_intra_process_) {
327 subscription_intra_process_->enable_callbacks();
329 for (
const auto & [_, event_ptr] : event_handlers_) {
338 std::shared_ptr<void> & message,
346 auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
348 std::chrono::time_point<std::chrono::system_clock> now;
349 if (subscription_topic_statistics_) {
352 now = std::chrono::system_clock::now();
355 any_callback_.dispatch(typed_message, message_info);
357 if (subscription_topic_statistics_) {
358 const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
359 const auto time =
rclcpp::Time(nanos.time_since_epoch().count());
365 handle_serialized_message(
366 const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
369 std::chrono::time_point<std::chrono::system_clock> now;
370 if (subscription_topic_statistics_) {
373 now = std::chrono::system_clock::now();
376 any_callback_.dispatch(serialized_message, message_info);
378 if (subscription_topic_statistics_) {
379 const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
380 const auto time =
rclcpp::Time(nanos.time_since_epoch().count());
386 handle_loaned_message(
387 void * loaned_message,
396 auto typed_message =
static_cast<ROSMessageType *
>(loaned_message);
398 auto sptr = std::shared_ptr<ROSMessageType>(
399 typed_message, [](ROSMessageType * msg) {(void) msg;});
401 std::chrono::time_point<std::chrono::system_clock> now;
402 if (subscription_topic_statistics_) {
405 now = std::chrono::system_clock::now();
408 any_callback_.dispatch(sptr, message_info);
410 if (subscription_topic_statistics_) {
411 const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
412 const auto time =
rclcpp::Time(nanos.time_since_epoch().count());
424 auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
425 message_memory_strategy_->return_message(typed_message);
435 message_memory_strategy_->return_serialized_message(message);
439 use_take_shared_method()
const
441 return any_callback_.use_take_shared_method();
447 rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
448 get_shared_dynamic_message_type()
override
451 "get_shared_dynamic_message_type is not implemented for Subscription");
454 rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
455 get_shared_dynamic_message()
override
458 "get_shared_dynamic_message is not implemented for Subscription");
461 rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
462 get_shared_dynamic_serialization_support()
override
465 "get_shared_dynamic_serialization_support is not implemented for Subscription");
468 rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr
472 "create_dynamic_message is not implemented for Subscription");
476 return_dynamic_message(
477 [[maybe_unused]] rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message)
override
480 "return_dynamic_message is not implemented for Subscription");
484 handle_dynamic_message(
485 [[maybe_unused]]
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
489 "handle_dynamic_message is not implemented for Subscription");
495 AnySubscriptionCallback<MessageT, AllocatorT> any_callback_;
502 typename message_memory_strategy::MessageMemoryStrategy<ROSMessageType, AllocatorT>::SharedPtr
503 message_memory_strategy_;
506 SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics_{
nullptr};
Additional meta data about messages taken from subscriptions.
const rmw_message_info_t & get_rmw_message_info() const
Return the message info as the underlying rmw message info type.
Encapsulation of Quality of Service settings.
RCLCPP_PUBLIC rclcpp::QoS get_actual_qos() const
Get the actual QoS settings, after the defaults have been determined.
virtual RCLCPP_PUBLIC void enable_callbacks()
Enable the callbacks to be called.
RCLCPP_PUBLIC void setup_intra_process(uint64_t intra_process_subscription_id, IntraProcessManagerWeakPtr weak_ipm)
Implemenation detail.
virtual RCLCPP_PUBLIC void disable_callbacks()
Disable callbacks from being called.
RCLCPP_PUBLIC bool take_type_erased(void *message_out, rclcpp::MessageInfo &message_info_out)
Take the next inter-process message from the subscription as a type erased pointer.
Subscription implementation, templated on the type of message this subscription receives.
std::enable_if_t< !rosidl_generator_traits::is_message< TakeT >::value &&std::is_same_v< TakeT, SubscribedType >, bool > take(TakeT &message_out, rclcpp::MessageInfo &message_info_out)
Take the next message from the inter-process subscription.
Subscription(rclcpp::node_interfaces::NodeBaseInterface *node_base, const rosidl_message_type_support_t &type_support_handle, const std::string &topic_name, const rclcpp::QoS &qos, AnySubscriptionCallback< MessageT, AllocatorT > callback, const rclcpp::SubscriptionOptionsWithAllocator< AllocatorT > &options, typename MessageMemoryStrategyT::SharedPtr message_memory_strategy, SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics=nullptr)
Default constructor.
void enable_callbacks() override
Enable the callbacks to be called.
void disable_callbacks() override
Disable callbacks from being called.
void return_serialized_message(std::shared_ptr< rclcpp::SerializedMessage > &message) override
Return the borrowed serialized message.
std::shared_ptr< rclcpp::SerializedMessage > create_serialized_message() override
Borrow a new serialized message.
void return_message(std::shared_ptr< void > &message) override
Return the borrowed message.
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override
Borrow a new serialized message (this clones!)
void post_init_setup([[maybe_unused]] rclcpp::node_interfaces::NodeBaseInterface *node_base, [[maybe_unused]] const rclcpp::QoS &qos, [[maybe_unused]] const rclcpp::SubscriptionOptionsWithAllocator< AllocatorT > &options)
Called after construction to continue setup that requires shared_from_this().
void handle_message(std::shared_ptr< void > &message, const rclcpp::MessageInfo &message_info) override
Check if we need to handle the message, and execute the callback if we do.
std::shared_ptr< void > create_message() override
Borrow a new message.
bool take(ROSMessageType &message_out, rclcpp::MessageInfo &message_info_out)
Take the next message from the inter-process subscription.
This class performs intra process communication between nodes.
Default allocation strategy for messages received by subscriptions.
Pure virtual interface class for the NodeBase part of the Node API.
Pure virtual interface class for the NodeTopics part of the Node API.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
DeliveredMessageKind
The kind of message that the subscription delivers in its callback, used by the executor.
Structure containing optional configuration for Subscriptions.
Template structure used to adapt custom, user-defined types to ROS types.