ROS 2 rclcpp + rcl - humble  humble
ROS 2 C++ Client Library with ROS Client Library
qos_event.hpp
1 // Copyright 2019 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 #ifndef RCLCPP__QOS_EVENT_HPP_
16 #define RCLCPP__QOS_EVENT_HPP_
17 
18 #include <functional>
19 #include <memory>
20 #include <mutex>
21 #include <stdexcept>
22 #include <string>
23 
24 #include "rcl/error_handling.h"
25 #include "rcl/event_callback.h"
26 #include "rmw/impl/cpp/demangle.hpp"
27 #include "rmw/incompatible_qos_events_statuses.h"
28 
29 #include "rcutils/logging_macros.h"
30 
31 #include "rclcpp/detail/cpp_callback_trampoline.hpp"
32 #include "rclcpp/exceptions.hpp"
33 #include "rclcpp/function_traits.hpp"
34 #include "rclcpp/logging.hpp"
35 #include "rclcpp/waitable.hpp"
36 
37 namespace rclcpp
38 {
39 
40 using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
41 using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
42 using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
43 using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
44 using QOSMessageLostInfo = rmw_message_lost_status_t;
45 using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
46 using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
47 
48 using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
49 using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
50 using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
51 using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
52 using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
53 using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
54 using QOSRequestedIncompatibleQoSCallbackType =
55  std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
56 
59 {
60  QOSDeadlineOfferedCallbackType deadline_callback;
61  QOSLivelinessLostCallbackType liveliness_callback;
62  QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
63 };
64 
67 {
68  QOSDeadlineRequestedCallbackType deadline_callback;
69  QOSLivelinessChangedCallbackType liveliness_callback;
70  QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
71  QOSMessageLostCallbackType message_lost_callback;
72 };
73 
74 class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
75 {
76 public:
77  RCLCPP_PUBLIC
79  rcl_ret_t ret,
80  const rcl_error_state_t * error_state,
81  const std::string & prefix);
82 
83  RCLCPP_PUBLIC
85  const exceptions::RCLErrorBase & base_exc,
86  const std::string & prefix);
87 };
88 
90 {
91 public:
92  enum class EntityType : std::size_t
93  {
94  Event,
95  };
96 
97  RCLCPP_PUBLIC
98  virtual ~QOSEventHandlerBase();
99 
101  RCLCPP_PUBLIC
102  size_t
103  get_number_of_ready_events() override;
104 
106  RCLCPP_PUBLIC
107  void
108  add_to_wait_set(rcl_wait_set_t * wait_set) override;
109 
111  RCLCPP_PUBLIC
112  bool
113  is_ready(rcl_wait_set_t * wait_set) override;
114 
116 
151  void
152  set_on_ready_callback(std::function<void(size_t, int)> callback) override
153  {
154  if (!callback) {
155  throw std::invalid_argument(
156  "The callback passed to set_on_ready_callback "
157  "is not callable.");
158  }
159 
160  // Note: we bind the int identifier argument to this waitable's entity types
161  auto new_callback =
162  [callback, this](size_t number_of_events) {
163  try {
164  callback(number_of_events, static_cast<int>(EntityType::Event));
165  } catch (const std::exception & exception) {
166  RCLCPP_ERROR_STREAM(
167  // TODO(wjwwood): get this class access to the node logger it is associated with
168  rclcpp::get_logger("rclcpp"),
169  "rclcpp::QOSEventHandlerBase@" << this <<
170  " caught " << rmw::impl::cpp::demangle(exception) <<
171  " exception in user-provided callback for the 'on ready' callback: " <<
172  exception.what());
173  } catch (...) {
174  RCLCPP_ERROR_STREAM(
175  rclcpp::get_logger("rclcpp"),
176  "rclcpp::QOSEventHandlerBase@" << this <<
177  " caught unhandled exception in user-provided callback " <<
178  "for the 'on ready' callback");
179  }
180  };
181 
182  std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
183 
184  // Set it temporarily to the new callback, while we replace the old one.
185  // This two-step setting, prevents a gap where the old std::function has
186  // been replaced but the middleware hasn't been told about the new one yet.
187  set_on_new_event_callback(
188  rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
189  static_cast<const void *>(&new_callback));
190 
191  // Store the std::function to keep it in scope, also overwrites the existing one.
192  on_new_event_callback_ = new_callback;
193 
194  // Set it again, now using the permanent storage.
195  set_on_new_event_callback(
196  rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
197  static_cast<const void *>(&on_new_event_callback_));
198  }
199 
201  void
203  {
204  std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
205  if (on_new_event_callback_) {
206  set_on_new_event_callback(nullptr, nullptr);
207  on_new_event_callback_ = nullptr;
208  }
209  }
210 
211 protected:
212  RCLCPP_PUBLIC
213  void
214  set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
215 
216  rcl_event_t event_handle_;
217  size_t wait_set_event_index_;
218  std::recursive_mutex callback_mutex_;
219  std::function<void(size_t)> on_new_event_callback_{nullptr};
220 };
221 
222 template<typename EventCallbackT, typename ParentHandleT>
224 {
225 public:
226  template<typename InitFuncT, typename EventTypeEnum>
228  const EventCallbackT & callback,
229  InitFuncT init_func,
230  ParentHandleT parent_handle,
231  EventTypeEnum event_type)
232  : parent_handle_(parent_handle), event_callback_(callback)
233  {
234  event_handle_ = rcl_get_zero_initialized_event();
235  rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
236  if (ret != RCL_RET_OK) {
237  if (ret == RCL_RET_UNSUPPORTED) {
238  UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
239  rcl_reset_error();
240  throw exc;
241  } else {
242  rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
243  }
244  }
245  }
246 
248  std::shared_ptr<void>
249  take_data() override
250  {
251  EventCallbackInfoT callback_info;
252  rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
253  if (ret != RCL_RET_OK) {
254  RCUTILS_LOG_ERROR_NAMED(
255  "rclcpp",
256  "Couldn't take event info: %s", rcl_get_error_string().str);
257  return nullptr;
258  }
259  return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
260  }
261 
262  std::shared_ptr<void>
263  take_data_by_entity_id(size_t id) override
264  {
265  (void)id;
266  return take_data();
267  }
268 
270  void
271  execute(std::shared_ptr<void> & data) override
272  {
273  if (!data) {
274  throw std::runtime_error("'data' is empty");
275  }
276  auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
277  event_callback_(*callback_ptr);
278  callback_ptr.reset();
279  }
280 
281 private:
282  using EventCallbackInfoT = typename std::remove_reference<typename
284 
285  ParentHandleT parent_handle_;
286  EventCallbackT event_callback_;
287 };
288 
289 } // namespace rclcpp
290 
291 #endif // RCLCPP__QOS_EVENT_HPP_
RCLCPP_PUBLIC bool is_ready(rcl_wait_set_t *wait_set) override
Check if the Waitable is ready.
Definition: qos_event.cpp:69
RCLCPP_PUBLIC void add_to_wait_set(rcl_wait_set_t *wait_set) override
Add the Waitable to a wait set.
Definition: qos_event.cpp:59
void set_on_ready_callback(std::function< void(size_t, int)> callback) override
Set a callback to be called when each new event instance occurs.
Definition: qos_event.hpp:152
RCLCPP_PUBLIC size_t get_number_of_ready_events() override
Get the number of ready events.
Definition: qos_event.cpp:52
void clear_on_ready_callback() override
Unset the callback registered for new events, if any.
Definition: qos_event.hpp:202
std::shared_ptr< void > take_data() override
Take data so that the callback cannot be scheduled again.
Definition: qos_event.hpp:249
void execute(std::shared_ptr< void > &data) override
Execute any entities of the Waitable that are ready.
Definition: qos_event.hpp:271
std::shared_ptr< void > take_data_by_entity_id(size_t id) override
Take the data so that it can be consumed with execute.
Definition: qos_event.hpp:263
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_take_event(const rcl_event_t *event, void *event_info)
Definition: event.c:151
RCL_PUBLIC RCL_WARN_UNUSED rcl_event_t rcl_get_zero_initialized_event(void)
Return a rcl_event_t struct with members set to NULL.
Definition: event.c:39
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC Logger get_logger(const std::string &name)
Return a named logger.
Definition: logger.cpp:27
Structure which encapsulates a ROS QoS event handle.
Definition: event.h:57
Container for subscription's, guard condition's, etc to be waited on.
Definition: wait.h:42
Contains callbacks for various types of events a Publisher can receive from the middleware.
Definition: qos_event.hpp:59
Contains callbacks for non-message events that a Subscription can receive from the middleware.
Definition: qos_event.hpp:67
#define RCL_RET_UNSUPPORTED
Unsupported return code.
Definition: types.h:36
#define RCL_RET_OK
Success return code.
Definition: types.h:26
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:23