ROS 2 rclcpp + rcl - lyrical  lyrical
ROS 2 C++ Client Library with ROS Client Library
subscription_intra_process_base.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__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
16 #define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
17 
18 #include <algorithm>
19 #include <memory>
20 #include <mutex>
21 #include <string>
22 #include <vector>
23 
24 #include "rcl/wait.h"
25 #include "rmw/impl/cpp/demangle.hpp"
26 
27 #include "rclcpp/guard_condition.hpp"
28 #include "rclcpp/logging.hpp"
29 #include "rclcpp/qos.hpp"
30 #include "rclcpp/waitable.hpp"
31 
32 namespace rclcpp
33 {
34 namespace experimental
35 {
36 
38 {
39 public:
40  RCLCPP_SMART_PTR_ALIASES_ONLY(SubscriptionIntraProcessBase)
41 
42  enum class EntityType : std::size_t
43  {
45  };
46 
47  RCLCPP_PUBLIC
49  rclcpp::Context::SharedPtr context,
50  const std::string & topic_name,
51  const rclcpp::QoS & qos_profile)
52  : gc_(context), topic_name_(topic_name), qos_profile_(qos_profile)
53  {}
54 
55  RCLCPP_PUBLIC
56  virtual ~SubscriptionIntraProcessBase() = default;
57 
58  RCLCPP_PUBLIC
59  size_t
60  get_number_of_ready_guard_conditions() override {return 1;}
61 
62  RCLCPP_PUBLIC
63  void
64  add_to_wait_set(rcl_wait_set_t & wait_set) override;
65 
66  RCLCPP_PUBLIC
67  virtual
68  size_t
69  available_capacity() const = 0;
70 
71  RCLCPP_PUBLIC
72  bool
73  is_durability_transient_local() const;
74 
75  bool
76  is_ready(const rcl_wait_set_t & wait_set) override = 0;
77 
78  std::shared_ptr<void>
79  take_data() override = 0;
80 
81  std::shared_ptr<void>
82  take_data_by_entity_id([[maybe_unused]] size_t id) override
83  {
84  return take_data();
85  }
86 
87  void
88  execute(const std::shared_ptr<void> & data) override = 0;
89 
91 
94  RCLCPP_PUBLIC
95  virtual
96  void disable_callbacks();
97 
99 
102  RCLCPP_PUBLIC
103  virtual
104  void enable_callbacks();
105 
106  virtual
107  bool
108  use_take_shared_method() const = 0;
109 
110  RCLCPP_PUBLIC
111  const char *
112  get_topic_name() const;
113 
114  RCLCPP_PUBLIC
115  QoS
116  get_actual_qos() const;
117 
119 
146  void
147  set_on_ready_callback(std::function<void(size_t, int)> callback) override
148  {
149  if (!callback) {
150  throw std::invalid_argument(
151  "The callback passed to set_on_ready_callback "
152  "is not callable.");
153  }
154 
155  // Note: we bind the int identifier argument to this waitable's entity types
156  auto new_callback =
157  [callback, this](size_t number_of_events) {
158  try {
159  callback(number_of_events, static_cast<int>(EntityType::Subscription));
160  } catch (const std::exception & exception) {
161  RCLCPP_ERROR_STREAM(
162  // TODO(wjwwood): get this class access to the node logger it is associated with
163  rclcpp::get_logger("rclcpp"),
164  "rclcpp::SubscriptionIntraProcessBase@" << this <<
165  " caught " << rmw::impl::cpp::demangle(exception) <<
166  " exception in user-provided callback for the 'on ready' callback: " <<
167  exception.what());
168  } catch (...) {
169  RCLCPP_ERROR_STREAM(
170  rclcpp::get_logger("rclcpp"),
171  "rclcpp::SubscriptionIntraProcessBase@" << this <<
172  " caught unhandled exception in user-provided callback " <<
173  "for the 'on ready' callback");
174  }
175  };
176 
177  std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
178  on_new_message_callback_ = new_callback;
179 
180  if (unread_count_ > 0) {
181  if (qos_profile_.history() == HistoryPolicy::KeepAll) {
182  on_new_message_callback_(unread_count_);
183  } else {
184  // Use qos profile depth as upper bound for unread_count_
185  on_new_message_callback_(std::min(unread_count_, qos_profile_.depth()));
186  }
187  unread_count_ = 0;
188  }
189  }
190 
192  void
194  {
195  std::lock_guard<std::recursive_mutex> lock(on_new_message_callback_mutex_);
196  on_new_message_callback_ = nullptr;
197  }
198 
199  RCLCPP_PUBLIC
200  std::vector<std::shared_ptr<rclcpp::TimerBase>>
201  get_timers() const override
202  {
203  return {};
204  }
205 
206 protected:
207  std::recursive_mutex on_new_message_callback_mutex_;
208  std::function<void(size_t)> on_new_message_callback_ {nullptr};
209  bool on_new_message_callback_disabled_{false};
210  size_t unread_count_{0};
212 
213  virtual void
214  trigger_guard_condition() = 0;
215 
216  void
217  invoke_on_new_message()
218  {
219  std::lock_guard<std::recursive_mutex> lock(this->on_new_message_callback_mutex_);
220  if (!on_new_message_callback_disabled_) {
221  if (this->on_new_message_callback_) {
222  this->on_new_message_callback_(1);
223  } else {
224  this->unread_count_++;
225  }
226  }
227  }
228 
229 private:
230  std::string topic_name_;
231  QoS qos_profile_;
232 };
233 
234 } // namespace experimental
235 } // namespace rclcpp
236 
237 #endif // RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
A condition that can be waited on in a single wait set and asynchronously triggered.
Encapsulation of Quality of Service settings.
Definition: qos.hpp:116
QoS & history(HistoryPolicy history)
Set the history policy.
Definition: qos.cpp:127
size_t depth() const
Get the history depth.
Definition: qos.cpp:289
Subscription implementation, templated on the type of message this subscription receives.
void execute(const std::shared_ptr< void > &data) override=0
Execute data that is passed in.
void clear_on_ready_callback() override
Unset the callback registered for new messages, if any.
bool is_ready(const rcl_wait_set_t &wait_set) override=0
Check if the Waitable is ready.
virtual RCLCPP_PUBLIC void enable_callbacks()
Enable the callbacks to be called.
virtual RCLCPP_PUBLIC void disable_callbacks()
Disable callbacks from being called.
void set_on_ready_callback(std::function< void(size_t, int)> callback) override
Set a callback to be called when each new message arrives.
RCLCPP_PUBLIC std::vector< std::shared_ptr< rclcpp::TimerBase > > get_timers() const override
Returns all timers used by this waitable.
RCLCPP_PUBLIC void add_to_wait_set(rcl_wait_set_t &wait_set) override
Add the Waitable to a wait set.
std::shared_ptr< void > take_data() override=0
Take the data so that it can be consumed with execute.
RCLCPP_PUBLIC size_t get_number_of_ready_guard_conditions() override
Get the number of ready guard_conditions.
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:34
Container for subscription's, guard condition's, etc to be waited on.
Definition: wait.h:42