ROS 2 rclcpp + rcl - rolling  rolling-20536064
ROS 2 C++ Client Library with ROS Client Library
subscription_base.cpp
1 // Copyright 2015 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "rclcpp/subscription_base.hpp"
16 
17 #include <cstdio>
18 #include <functional>
19 #include <memory>
20 #include <stdexcept>
21 #include <string>
22 #include <unordered_map>
23 #include <vector>
24 
25 #include "rcpputils/scope_exit.hpp"
26 
27 #include "rclcpp/detail/cpp_callback_trampoline.hpp"
28 #include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
29 #include "rclcpp/exceptions.hpp"
30 #include "rclcpp/expand_topic_or_service_name.hpp"
31 #include "rclcpp/experimental/intra_process_manager.hpp"
32 #include "rclcpp/logging.hpp"
33 #include "rclcpp/node_interfaces/node_base_interface.hpp"
34 #include "rclcpp/event_handler.hpp"
35 
36 #include "rcl/event.h"
37 #include "rmw/error_handling.h"
38 #include "rmw/impl/cpp/demangle.hpp"
39 #include "rmw/rmw.h"
40 
41 #include "rosidl_dynamic_typesupport/types.h"
42 
44 
45 SubscriptionBase::SubscriptionBase(
47  const rosidl_message_type_support_t & type_support_handle,
48  const std::string & topic_name,
49  const rcl_subscription_options_t & subscription_options,
50  const SubscriptionEventCallbacks & event_callbacks,
51  bool use_default_callbacks,
52  DeliveredMessageKind delivered_message_kind)
53 : node_base_(node_base),
54  node_handle_(node_base_->get_shared_rcl_node_handle()),
55  node_logger_(rclcpp::get_node_logger(node_handle_.get())),
56  use_intra_process_(false),
57  intra_process_subscription_id_(0),
58  event_callbacks_(event_callbacks),
59  type_support_(type_support_handle),
60  delivered_message_kind_(delivered_message_kind)
61 {
62  auto custom_deletor = [node_handle = this->node_handle_](rcl_subscription_t * rcl_subs)
63  {
64  if (rcl_subscription_fini(rcl_subs, node_handle.get()) != RCL_RET_OK) {
65  RCLCPP_ERROR(
66  rclcpp::get_node_logger(node_handle.get()).get_child("rclcpp"),
67  "Error in destruction of rcl subscription handle: %s",
68  rcl_get_error_string().str);
69  rcl_reset_error();
70  }
71  delete rcl_subs;
72  };
73 
74  subscription_handle_ = std::shared_ptr<rcl_subscription_t>(
75  new rcl_subscription_t, custom_deletor);
76  *subscription_handle_.get() = rcl_get_zero_initialized_subscription();
77 
79  subscription_handle_.get(),
80  node_handle_.get(),
81  &type_support_handle,
82  topic_name.c_str(),
83  &subscription_options);
84  if (ret != RCL_RET_OK) {
85  if (ret == RCL_RET_TOPIC_NAME_INVALID) {
86  auto rcl_node_handle = node_handle_.get();
87  // this will throw on any validation problem
88  rcl_reset_error();
90  topic_name,
91  rcl_node_get_name(rcl_node_handle),
92  rcl_node_get_namespace(rcl_node_handle));
93  }
94  rclcpp::exceptions::throw_from_rcl_error(ret, "could not create subscription");
95  }
96 
97  bind_event_callbacks(event_callbacks_, use_default_callbacks);
98 }
99 
101 {
102  if (!use_intra_process_) {
103  return;
104  }
105  auto ipm = weak_ipm_.lock();
106  if (!ipm) {
107  // TODO(ivanpauno): should this raise an error?
108  RCLCPP_WARN(
109  rclcpp::get_logger("rclcpp"),
110  "Intra process manager died before than a subscription.");
111  return;
112  }
113  ipm->remove_subscription(intra_process_subscription_id_);
114 }
115 
116 bool
118 {
119  return rcl_subscription_event_type_is_supported(event_type);
120 }
121 
122 void
124  const SubscriptionEventCallbacks & event_callbacks, bool use_default_callbacks)
125 {
126  try {
127  if (event_callbacks.deadline_callback) {
128  this->add_event_handler(
129  event_callbacks.deadline_callback,
130  RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
131  }
132  } catch (const UnsupportedEventTypeException & /*exc*/) {
133  RCLCPP_WARN(
134  rclcpp::get_logger("rclcpp"),
135  "Failed to add event handler for deadline; not supported");
136  }
137 
138  try {
139  if (event_callbacks.liveliness_callback) {
140  this->add_event_handler(
141  event_callbacks.liveliness_callback,
142  RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
143  }
144  } catch (const UnsupportedEventTypeException & /*exc*/) {
145  RCLCPP_WARN(
146  rclcpp::get_logger("rclcpp"),
147  "Failed to add event handler for liveliness; not supported");
148  }
149 
150  QOSRequestedIncompatibleQoSCallbackType incompatible_qos_cb;
151  if (event_callbacks.incompatible_qos_callback) {
152  incompatible_qos_cb = event_callbacks.incompatible_qos_callback;
153  } else if (use_default_callbacks) {
154  // Register default callback when not specified
155  incompatible_qos_cb = [this](QOSRequestedIncompatibleQoSInfo & info) {
156  this->default_incompatible_qos_callback(info);
157  };
158  }
159  // Register default callback when not specified
160  try {
161  if (incompatible_qos_cb) {
162  this->add_event_handler(incompatible_qos_cb, RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
163  }
164  } catch (const UnsupportedEventTypeException & /*exc*/) {
165  RCLCPP_WARN(
166  rclcpp::get_logger("rclcpp"),
167  "Failed to add event handler for incompatible qos; not supported");
168  }
169 
170  IncompatibleTypeCallbackType incompatible_type_cb;
171  if (event_callbacks.incompatible_type_callback) {
172  incompatible_type_cb = event_callbacks.incompatible_type_callback;
173  } else if (use_default_callbacks) {
174  // Register default callback when not specified
175  incompatible_type_cb = [this](IncompatibleTypeInfo & info) {
176  this->default_incompatible_type_callback(info);
177  };
178  }
179  try {
180  if (incompatible_type_cb) {
181  this->add_event_handler(incompatible_type_cb, RCL_SUBSCRIPTION_INCOMPATIBLE_TYPE);
182  }
183  } catch (UnsupportedEventTypeException & /*exc*/) {
184  RCLCPP_WARN(
185  rclcpp::get_logger("rclcpp"),
186  "Failed to add event handler for incompatible type; not supported");
187  }
188 
189  try {
190  if (event_callbacks.message_lost_callback) {
191  this->add_event_handler(
192  event_callbacks.message_lost_callback,
193  RCL_SUBSCRIPTION_MESSAGE_LOST);
194  }
195  } catch (const UnsupportedEventTypeException & /*exc*/) {
196  RCLCPP_WARN(
197  rclcpp::get_logger("rclcpp"),
198  "Failed to add event handler for message lost; not supported");
199  }
200 
201  try {
202  if (event_callbacks.matched_callback) {
203  this->add_event_handler(
204  event_callbacks.matched_callback,
205  RCL_SUBSCRIPTION_MATCHED);
206  }
207  } catch (const UnsupportedEventTypeException & /*exc*/) {
208  RCLCPP_WARN(
209  rclcpp::get_logger("rclcpp"),
210  "Failed to add event handler for matched; not supported");
211  }
212 }
213 
214 const char *
216 {
217  return rcl_subscription_get_topic_name(subscription_handle_.get());
218 }
219 
220 std::shared_ptr<rcl_subscription_t>
221 SubscriptionBase::get_subscription_handle()
222 {
223  return subscription_handle_;
224 }
225 
226 std::shared_ptr<const rcl_subscription_t>
227 SubscriptionBase::get_subscription_handle() const
228 {
229  return subscription_handle_;
230 }
231 
232 const
233 std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
235 {
236  return event_handlers_;
237 }
238 
241 {
242  const rmw_qos_profile_t * qos = rcl_subscription_get_actual_qos(subscription_handle_.get());
243  if (!qos) {
244  auto msg = std::string("failed to get qos settings: ") + rcl_get_error_string().str;
245  rcl_reset_error();
246  throw std::runtime_error(msg);
247  }
248 
250 }
251 
252 bool
253 SubscriptionBase::take_type_erased(void * message_out, rclcpp::MessageInfo & message_info_out)
254 {
255  rcl_ret_t ret = rcl_take(
256  this->get_subscription_handle().get(),
257  message_out,
258  &message_info_out.get_rmw_message_info(),
259  nullptr // rmw_subscription_allocation_t is unused here
260  );
261  TRACETOOLS_TRACEPOINT(rclcpp_take, static_cast<const void *>(message_out));
263  return false;
264  } else if (RCL_RET_OK != ret) {
265  rclcpp::exceptions::throw_from_rcl_error(ret);
266  }
267  if (
268  matches_any_intra_process_publishers(&message_info_out.get_rmw_message_info().publisher_gid))
269  {
270  // In this case, the message will be delivered via intra-process and
271  // we should ignore this copy of the message.
272  return false;
273  }
274  return true;
275 }
276 
277 bool
279  rclcpp::SerializedMessage & message_out,
280  rclcpp::MessageInfo & message_info_out)
281 {
283  this->get_subscription_handle().get(),
284  &message_out.get_rcl_serialized_message(),
285  &message_info_out.get_rmw_message_info(),
286  nullptr);
287  TRACETOOLS_TRACEPOINT(
288  rclcpp_take,
289  static_cast<const void *>(&message_out.get_rcl_serialized_message()));
291  return false;
292  } else if (RCL_RET_OK != ret) {
293  rclcpp::exceptions::throw_from_rcl_error(ret);
294  }
295  return true;
296 }
297 
298 const rosidl_message_type_support_t &
299 SubscriptionBase::get_message_type_support_handle() const
300 {
301  return type_support_;
302 }
303 
304 bool
306 {
307  return delivered_message_kind_ == rclcpp::DeliveredMessageKind::SERIALIZED_MESSAGE;
308 }
309 
312 {
313  return delivered_message_kind_;
314 }
315 
316 size_t
318 {
319  size_t inter_process_publisher_count = 0;
320 
321  rmw_ret_t status = rcl_subscription_get_publisher_count(
322  subscription_handle_.get(),
323  &inter_process_publisher_count);
324 
325  if (RCL_RET_OK != status) {
326  rclcpp::exceptions::throw_from_rcl_error(status, "failed to get get publisher count");
327  }
328  return inter_process_publisher_count;
329 }
330 
331 void
333  uint64_t intra_process_subscription_id,
334  IntraProcessManagerWeakPtr weak_ipm)
335 {
336  intra_process_subscription_id_ = intra_process_subscription_id;
337  weak_ipm_ = std::move(weak_ipm);
338  use_intra_process_ = true;
339 }
340 
341 bool
343 {
344  bool retval = rcl_subscription_can_loan_messages(subscription_handle_.get());
345  if (retval) {
346  // TODO(clalancette): The loaned message interface is currently not safe to use with
347  // shared_ptr callbacks. If a user takes a copy of the shared_ptr, it can get freed from
348  // underneath them via rcl_return_loaned_message_from_subscription(). The correct solution is
349  // to return the loaned message in a custom deleter, but that needs to be carefully handled
350  // with locking. Warn the user about this until we fix it.
351  RCLCPP_WARN_ONCE(
352  this->node_logger_,
353  "Loaned messages are only safe with const ref subscription callbacks. "
354  "If you are using any other kind of subscriptions, "
355  "set the ROS_DISABLE_LOANED_MESSAGES environment variable to 1 (the default).");
356  }
357  return retval;
358 }
359 
360 rclcpp::Waitable::SharedPtr
362 {
363  // If not using intra process, shortcut to nullptr.
364  if (!use_intra_process_) {
365  return nullptr;
366  }
367  // Get the intra process manager.
368  auto ipm = weak_ipm_.lock();
369  if (!ipm) {
370  throw std::runtime_error(
371  "SubscriptionBase::get_intra_process_waitable() called "
372  "after destruction of intra process manager");
373  }
374 
375  // Use the id to retrieve the subscription intra-process from the intra-process manager.
376  return ipm->get_subscription_intra_process(intra_process_subscription_id_);
377 }
378 
379 void
380 SubscriptionBase::default_incompatible_qos_callback(
381  rclcpp::QOSRequestedIncompatibleQoSInfo & event) const
382 {
383  std::string policy_name = qos_policy_name_from_kind(event.last_policy_kind);
384  RCLCPP_WARN(
385  rclcpp::get_logger(rcl_node_get_logger_name(node_handle_.get())),
386  "New publisher discovered on topic '%s', offering incompatible QoS. "
387  "No messages will be sent to it. "
388  "Last incompatible policy: %s",
389  get_topic_name(),
390  policy_name.c_str());
391 }
392 
393 void
394 SubscriptionBase::default_incompatible_type_callback(
395  [[maybe_unused]] rclcpp::IncompatibleTypeInfo & event) const
396 {
397  RCLCPP_WARN(
398  rclcpp::get_logger(rcl_node_get_logger_name(node_handle_.get())),
399  "Incompatible type on topic '%s', no messages will be sent to it.", get_topic_name());
400 }
401 
402 bool
403 SubscriptionBase::matches_any_intra_process_publishers(const rmw_gid_t * sender_gid) const
404 {
405  if (!use_intra_process_) {
406  return false;
407  }
408  auto ipm = weak_ipm_.lock();
409  if (!ipm) {
410  throw std::runtime_error(
411  "intra process publisher check called "
412  "after destruction of intra process manager");
413  }
414  return ipm->matches_any_publishers(sender_gid);
415 }
416 
417 bool
419  void * pointer_to_subscription_part,
420  bool in_use_state)
421 {
422  if (nullptr == pointer_to_subscription_part) {
423  throw std::invalid_argument("pointer_to_subscription_part is unexpectedly nullptr");
424  }
425  if (this == pointer_to_subscription_part) {
426  return subscription_in_use_by_wait_set_.exchange(in_use_state);
427  }
428  if (get_intra_process_waitable().get() == pointer_to_subscription_part) {
429  return intra_process_subscription_waitable_in_use_by_wait_set_.exchange(in_use_state);
430  }
431  for (const auto & key_event_pair : event_handlers_) {
432  auto qos_event = key_event_pair.second;
433  if (qos_event.get() == pointer_to_subscription_part) {
434  return qos_events_in_use_by_wait_set_[qos_event.get()].exchange(in_use_state);
435  }
436  }
437  throw std::runtime_error("given pointer_to_subscription_part does not match any part");
438 }
439 
440 std::vector<rclcpp::NetworkFlowEndpoint>
442 {
443  rcutils_allocator_t allocator = rcutils_get_default_allocator();
444  rcl_network_flow_endpoint_array_t network_flow_endpoint_array =
445  rcl_get_zero_initialized_network_flow_endpoint_array();
446  rcl_ret_t ret = rcl_subscription_get_network_flow_endpoints(
447  subscription_handle_.get(), &allocator, &network_flow_endpoint_array);
448  if (RCL_RET_OK != ret) {
449  auto error_msg = std::string("Error obtaining network flows of subscription: ") +
450  rcl_get_error_string().str;
451  rcl_reset_error();
452  if (RCL_RET_OK !=
453  rcl_network_flow_endpoint_array_fini(&network_flow_endpoint_array))
454  {
455  error_msg += std::string(". Also error cleaning up network flow array: ") +
456  rcl_get_error_string().str;
457  rcl_reset_error();
458  }
459  rclcpp::exceptions::throw_from_rcl_error(ret, error_msg);
460  }
461 
462  std::vector<rclcpp::NetworkFlowEndpoint> network_flow_endpoint_vector;
463  network_flow_endpoint_vector.reserve(network_flow_endpoint_array.size);
464  for (size_t i = 0; i < network_flow_endpoint_array.size; ++i) {
465  network_flow_endpoint_vector.emplace_back(
466  network_flow_endpoint_array.
467  network_flow_endpoint[i]);
468  }
469 
470  ret = rcl_network_flow_endpoint_array_fini(&network_flow_endpoint_array);
471  if (RCL_RET_OK != ret) {
472  rclcpp::exceptions::throw_from_rcl_error(ret, "error cleaning up network flow array");
473  }
474 
475  return network_flow_endpoint_vector;
476 }
477 
478 void
480  rcl_event_callback_t callback,
481  const void * user_data)
482 {
484  subscription_handle_.get(),
485  callback,
486  user_data);
487 
488  if (RCL_RET_OK != ret) {
489  using rclcpp::exceptions::throw_from_rcl_error;
490  throw_from_rcl_error(ret, "failed to set the on new message callback for subscription");
491  }
492 }
493 
494 bool
496 {
497  return rcl_subscription_is_cft_supported(subscription_handle_.get());
498 }
499 
500 bool
502 {
503  return rcl_subscription_is_cft_enabled(subscription_handle_.get());
504 }
505 
506 void
508  const std::string & filter_expression,
509  const std::vector<std::string> & expression_parameters)
510 {
513 
514  std::vector<const char *> cstrings = get_c_vector_string(expression_parameters);
516  subscription_handle_.get(),
517  get_c_string(filter_expression),
518  cstrings.size(),
519  cstrings.data(),
520  &options);
521  if (RCL_RET_OK != ret) {
522  rclcpp::exceptions::throw_from_rcl_error(
523  ret, "failed to init subscription content_filtered_topic option");
524  }
525  RCPPUTILS_SCOPE_EXIT(
526  {
528  subscription_handle_.get(), &options);
529  if (RCL_RET_OK != ret) {
530  RCLCPP_ERROR(
531  rclcpp::get_logger("rclcpp"),
532  "Failed to fini subscription content_filtered_topic option: %s",
533  rcl_get_error_string().str);
534  rcl_reset_error();
535  }
536  });
537 
539  subscription_handle_.get(),
540  &options);
541 
542  if (RCL_RET_OK != ret) {
543  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to set cft expression parameters");
544  }
545 }
546 
549 {
550  rclcpp::ContentFilterOptions ret_options;
553 
555  subscription_handle_.get(),
556  &options);
557 
558  if (RCL_RET_OK != ret) {
559  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to get cft expression parameters");
560  }
561 
562  RCPPUTILS_SCOPE_EXIT(
563  {
565  subscription_handle_.get(), &options);
566  if (RCL_RET_OK != ret) {
567  RCLCPP_ERROR(
568  rclcpp::get_logger("rclcpp"),
569  "Failed to fini subscription content_filtered_topic option: %s",
570  rcl_get_error_string().str);
571  rcl_reset_error();
572  }
573  });
574 
575  rmw_subscription_content_filter_options_t & content_filter_options =
576  options.rmw_subscription_content_filter_options;
577  ret_options.filter_expression = content_filter_options.filter_expression;
578 
579  for (size_t i = 0; i < content_filter_options.expression_parameters.size; ++i) {
580  ret_options.expression_parameters.push_back(
581  content_filter_options.expression_parameters.data[i]);
582  }
583 
584  return ret_options;
585 }
586 
587 
588 // DYNAMIC TYPE ==================================================================================
589 bool
590 SubscriptionBase::take_dynamic_message(
592  rclcpp::MessageInfo & /*message_info_out*/)
593 {
594  throw std::runtime_error("Unimplemented");
595  return false;
596 }
597 
598 void
600 {
601  // Temporary remove the on_new_message_callback_ to prevent it from being called
602  std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
603  if (on_new_message_callback_) {
604  set_on_new_message_callback(nullptr, nullptr);
605  }
606 }
607 
608 void
610 {
611  // Set callback again if it was previously removed in disable_callbacks()
612  std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
613  if (on_new_message_callback_) {
615  rclcpp::detail::cpp_callback_trampoline<
616  decltype(on_new_message_callback_), const void *, size_t>,
617  static_cast<const void *>(&on_new_message_callback_));
618  }
619 }
620 
621 void
622 SubscriptionBase::set_on_new_message_callback(const std::function<void(size_t)> & callback)
623 {
624  if (!callback) {
625  throw std::invalid_argument(
626  "The callback passed to set_on_new_message_callback "
627  "is not callable.");
628  }
629 
630  auto new_callback =
631  [callback, this](size_t number_of_messages) {
632  try {
633  callback(number_of_messages);
634  } catch (const std::exception & exception) {
635  RCLCPP_ERROR_STREAM(
636  node_logger_,
637  "rclcpp::SubscriptionBase@" << this <<
638  " caught " << rmw::impl::cpp::demangle(exception) <<
639  " exception in user-provided callback for the 'on new message' callback: " <<
640  exception.what());
641  } catch (...) {
642  RCLCPP_ERROR_STREAM(
643  node_logger_,
644  "rclcpp::SubscriptionBase@" << this <<
645  " caught unhandled exception in user-provided callback " <<
646  "for the 'on new message' callback");
647  }
648  };
649 
650  std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
651 
652  // Set it temporarily to the new callback, while we replace the old one.
653  // This two-step setting, prevents a gap where the old std::function has
654  // been replaced but the middleware hasn't been told about the new one yet.
656  rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
657  static_cast<const void *>(&new_callback));
658 
659  // Store the std::function to keep it in scope, also overwrites the existing one.
660  on_new_message_callback_ = new_callback;
661 
662  // Set it again, now using the permanent storage.
664  rclcpp::detail::cpp_callback_trampoline<
665  decltype(on_new_message_callback_), const void *, size_t>,
666  static_cast<const void *>(&on_new_message_callback_));
667 }
668 
669 void
671 {
672  std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
673 
674  if (on_new_message_callback_) {
675  set_on_new_message_callback(nullptr, nullptr);
676  on_new_message_callback_ = nullptr;
677  }
678 }
679 
680 void
682  const std::function<void(size_t)> & callback)
683 {
684  if (!use_intra_process_) {
685  RCLCPP_WARN(
686  rclcpp::get_logger("rclcpp"),
687  "Calling set_on_new_intra_process_message_callback for subscription with IPC disabled");
688  return;
689  }
690 
691  if (!callback) {
692  throw std::invalid_argument(
693  "The callback passed to set_on_new_intra_process_message_callback "
694  "is not callable.");
695  }
696 
697  // The on_ready_callback signature has an extra `int` argument used to disambiguate between
698  // possible different entities within a generic waitable.
699  // We hide that detail to users of this method.
700  std::function<void(size_t, int)> new_callback = [callback] (size_t nr, int) {callback(nr);};
701  subscription_intra_process_->set_on_ready_callback(new_callback);
702 }
703 
704 void
706 {
707  if (!use_intra_process_) {
708  RCLCPP_WARN(
709  rclcpp::get_logger("rclcpp"),
710  "Calling clear_on_new_intra_process_message_callback for subscription with IPC disabled");
711  return;
712  }
713 
714  subscription_intra_process_->clear_on_ready_callback();
715 }
716 
717 void
719  const std::function<void(size_t)> & callback,
721 {
722  if (event_handlers_.count(event_type) == 0) {
723  RCLCPP_WARN(
724  rclcpp::get_logger("rclcpp"),
725  "Calling set_on_new_qos_event_callback for non registered subscription event_type");
726  return;
727  }
728 
729  if (!callback) {
730  throw std::invalid_argument(
731  "The callback passed to set_on_new_qos_event_callback "
732  "is not callable.");
733  }
734 
735  // The on_ready_callback signature has an extra `int` argument used to disambiguate between
736  // possible different entities within a generic waitable.
737  // We hide that detail to users of this method.
738  std::function<void(size_t, int)> new_callback = [callback] (size_t nr, int) {callback(nr);};
739  event_handlers_[event_type]->set_on_ready_callback(new_callback);
740 }
741 
742 void
744 {
745  if (event_handlers_.count(event_type) == 0) {
746  RCLCPP_WARN(
747  rclcpp::get_logger("rclcpp"),
748  "Calling clear_on_new_qos_event_callback for non registered event_type");
749  return;
750  }
751 
752  event_handlers_[event_type]->clear_on_ready_callback();
753 }
RCLCPP_PUBLIC Logger get_child(const std::string &suffix)
Return a logger that is a descendant of this logger.
Definition: logger.cpp:57
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.
Definition: qos.hpp:114
Object oriented version of rcl_serialized_message_t with destructor to avoid memory leaks.
rcl_serialized_message_t & get_rcl_serialized_message()
Get the underlying rcl_serialized_t handle.
RCLCPP_PUBLIC size_t get_publisher_count() const
Get matching publisher count.
RCLCPP_PUBLIC rclcpp::QoS get_actual_qos() const
Get the actual QoS settings, after the defaults have been determined.
RCLCPP_PUBLIC void set_on_new_message_callback(const std::function< void(size_t)> &callback)
Set a callback to be called when each new message is received.
RCLCPP_PUBLIC void clear_on_new_message_callback()
Unset the callback registered for new messages, if any.
RCLCPP_PUBLIC void set_on_new_qos_event_callback(const std::function< void(size_t)> &callback, rcl_subscription_event_type_t event_type)
Set a callback to be called when each new qos event instance occurs.
virtual RCLCPP_PUBLIC void enable_callbacks()
Enable the callbacks to be called.
RCLCPP_PUBLIC bool can_loan_messages() const
Check if subscription instance can loan messages.
static RCLCPP_PUBLIC bool event_type_is_supported(const rcl_subscription_event_type_t event_type)
Check if a subscription event type is supported by the active RMW implementation.
RCLCPP_PUBLIC bool is_cft_supported() const
Check if content filtered topic feature of the subscription instance is supported.
RCLCPP_PUBLIC rclcpp::Waitable::SharedPtr get_intra_process_waitable() const
Return the waitable for intra-process.
RCLCPP_PUBLIC std::vector< rclcpp::NetworkFlowEndpoint > get_network_flow_endpoints() const
Get network flow endpoints.
RCLCPP_PUBLIC void setup_intra_process(uint64_t intra_process_subscription_id, IntraProcessManagerWeakPtr weak_ipm)
Implemenation detail.
RCLCPP_PUBLIC DeliveredMessageKind get_delivered_message_kind() const
Return the delivered message kind.
RCLCPP_PUBLIC void set_on_new_intra_process_message_callback(const std::function< void(size_t)> &callback)
Set a callback to be called when each new intra-process message is received.
virtual RCLCPP_PUBLIC void disable_callbacks()
Disable callbacks from being called.
RCLCPP_PUBLIC void clear_on_new_qos_event_callback(rcl_subscription_event_type_t event_type)
Unset the callback registered for new qos events, if any.
RCLCPP_PUBLIC bool take_serialized(rclcpp::SerializedMessage &message_out, rclcpp::MessageInfo &message_info_out)
Take the next inter-process message, in its serialized form, from the subscription.
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.
RCLCPP_PUBLIC bool exchange_in_use_by_wait_set_state(void *pointer_to_subscription_part, bool in_use_state)
Exchange state of whether or not a part of the subscription is used by a wait set.
RCLCPP_PUBLIC void set_content_filter(const std::string &filter_expression, const std::vector< std::string > &expression_parameters={})
Set the filter expression and expression parameters for the subscription.
virtual RCLCPP_PUBLIC ~SubscriptionBase()
Destructor.
RCLCPP_PUBLIC bool is_cft_enabled() const
Check if content filtered topic feature of the subscription instance is enabled.
RCLCPP_PUBLIC void bind_event_callbacks(const SubscriptionEventCallbacks &event_callbacks, bool use_default_callbacks)
Add event handlers for passed in event_callbacks.
RCLCPP_PUBLIC const std::unordered_map< rcl_subscription_event_type_t, std::shared_ptr< rclcpp::EventHandlerBase > > & get_event_handlers() const
Get all the QoS event handlers associated with this subscription.
RCLCPP_PUBLIC void clear_on_new_intra_process_message_callback()
Unset the callback registered for new intra-process messages, if any.
RCLCPP_PUBLIC rclcpp::ContentFilterOptions get_content_filter() const
Get the filter expression and expression parameters for the subscription.
RCLCPP_PUBLIC bool is_serialized() const
Return if the subscription is serialized.
RCLCPP_PUBLIC const char * get_topic_name() const
Get the topic that this subscription is subscribed on.
Pure virtual interface class for the NodeBase part of the Node API.
enum rcl_subscription_event_type_e rcl_subscription_event_type_t
Enumeration of all of the subscription events that may fire.
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_subscription_event_type_is_supported(const rcl_subscription_event_type_t event_type)
Check if a subscription event type is supported by the active RMW implementation.
Definition: event.c:261
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC std::string expand_topic_or_service_name(const std::string &name, const std::string &node_name, const std::string &namespace_, bool is_service=false)
Expand a topic or service name and throw if it is not valid.
RCLCPP_PUBLIC Logger get_node_logger(const rcl_node_t *node)
Return a named logger using an rcl_node_t.
Definition: logger.cpp:43
DeliveredMessageKind
The kind of message that the subscription delivers in its callback, used by the executor.
RCLCPP_PUBLIC std::vector< const char * > get_c_vector_string(const std::vector< std::string > &strings_in)
Return the std::vector of C string from the given std::vector<std::string>.
Definition: utilities.cpp:214
RCLCPP_PUBLIC const char * get_c_string(const char *string_in)
Return the given string.
Definition: utilities.cpp:202
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Definition: logger.cpp:32
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_name(const rcl_node_t *node)
Return the name of the node.
Definition: node.c:416
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_namespace(const rcl_node_t *node)
Return the namespace of the node.
Definition: node.c:425
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_logger_name(const rcl_node_t *node)
Return the logger name of the node.
Definition: node.c:493
Options available for a rcl subscription.
Definition: subscription.h:47
Structure which encapsulates a ROS Subscription.
Definition: subscription.h:40
Options to configure content filtered topic in the subscription.
std::string filter_expression
Filter expression is similar to the WHERE part of an SQL clause.
static QoSInitialization from_rmw(const rmw_qos_profile_t &rmw_qos)
Create a QoSInitialization from an existing rmw_qos_profile_t, using its history and depth.
Definition: qos.cpp:70
Contains callbacks for non-message events that a Subscription can receive from the middleware.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_content_filter_options_fini(const rcl_subscription_t *subscription, rcl_subscription_content_filter_options_t *options)
Reclaim rcl_subscription_content_filter_options_t structure.
Definition: subscription.c:493
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_init(rcl_subscription_t *subscription, const rcl_node_t *node, const rosidl_message_type_support_t *type_support, const char *topic_name, const rcl_subscription_options_t *options)
Initialize a ROS subscription.
Definition: subscription.c:51
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_subscription_get_topic_name(const rcl_subscription_t *subscription)
Get the topic name for the subscription.
Definition: subscription.c:779
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_set_on_new_message_callback(const rcl_subscription_t *subscription, rcl_event_callback_t callback, const void *user_data)
Set the on new message callback function for the subscription.
Definition: subscription.c:862
RCL_PUBLIC bool rcl_subscription_can_loan_messages(const rcl_subscription_t *subscription)
Check if subscription instance can loan messages.
Definition: subscription.c:848
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_fini(rcl_subscription_t *subscription, rcl_node_t *node)
Finalize a rcl_subscription_t.
Definition: subscription.c:181
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take(const rcl_subscription_t *subscription, void *ros_message, rmw_message_info_t *message_info, rmw_subscription_allocation_t *allocation)
Take a ROS message from a topic using a rcl subscription.
Definition: subscription.c:580
RCL_PUBLIC RCL_WARN_UNUSED rmw_ret_t rcl_subscription_get_publisher_count(const rcl_subscription_t *subscription, size_t *publisher_count)
Get the number of publishers matched to a subscription.
Definition: subscription.c:817
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_serialized_message(const rcl_subscription_t *subscription, rcl_serialized_message_t *serialized_message, rmw_message_info_t *message_info, rmw_subscription_allocation_t *allocation)
Take a serialized raw message from a topic using a rcl subscription.
Definition: subscription.c:661
RCL_PUBLIC RCL_WARN_UNUSED rcl_subscription_content_filter_options_t rcl_get_zero_initialized_subscription_content_filter_options(void)
Return the zero initialized subscription content filter options.
Definition: subscription.c:425
RCL_PUBLIC RCL_WARN_UNUSED bool rcl_subscription_is_cft_enabled(const rcl_subscription_t *subscription)
Check if the content filtered topic feature is enabled in the subscription.
Definition: subscription.c:513
RCL_PUBLIC RCL_WARN_UNUSED const rmw_qos_profile_t * rcl_subscription_get_actual_qos(const rcl_subscription_t *subscription)
Get the actual qos settings of the subscription.
Definition: subscription.c:839
RCL_PUBLIC RCL_WARN_UNUSED rcl_subscription_t rcl_get_zero_initialized_subscription(void)
Return a rcl_subscription_t struct with members set to NULL.
Definition: subscription.c:43
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_get_content_filter(const rcl_subscription_t *subscription, rcl_subscription_content_filter_options_t *options)
Retrieve the filter expression of the subscription.
Definition: subscription.c:556
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_set_content_filter(const rcl_subscription_t *subscription, const rcl_subscription_content_filter_options_t *options)
Set the filter expression and expression parameters for the subscription.
Definition: subscription.c:522
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_subscription_content_filter_options_init(const rcl_subscription_t *subscription, const char *filter_expression, size_t expression_parameters_argc, const char *expression_parameter_argv[], rcl_subscription_content_filter_options_t *options)
Initialize the content filter options for the given subscription options.
Definition: subscription.c:434
RCL_PUBLIC bool rcl_subscription_is_cft_supported(const rcl_subscription_t *subscription)
Check if subscription instance supports content filtering.
Definition: subscription.c:879
#define RCL_RET_SUBSCRIPTION_TAKE_FAILED
Failed to take a message from the subscription return code.
Definition: types.h:75
#define RCL_RET_OK
Success return code.
Definition: types.h:27
#define RCL_RET_TOPIC_NAME_INVALID
Topic name does not pass validation.
Definition: types.h:47
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24