ROS 2 rclcpp + rcl - rolling  rolling-29de98cf
ROS 2 C++ Client Library with ROS Client Library
timer.hpp
1 // Copyright 2014 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__TIMER_HPP_
16 #define RCLCPP__TIMER_HPP_
17 
18 #include <atomic>
19 #include <chrono>
20 #include <functional>
21 #include <optional>
22 #include <memory>
23 #include <thread>
24 #include <type_traits>
25 #include <utility>
26 
27 #include "rclcpp/clock.hpp"
28 #include "rclcpp/context.hpp"
29 #include "rclcpp/function_traits.hpp"
30 #include "rclcpp/macros.hpp"
31 #include "rclcpp/utilities.hpp"
32 #include "rclcpp/visibility_control.hpp"
33 #include "tracetools/tracetools.h"
34 #include "tracetools/utils.hpp"
35 
36 #include "rcl/error_handling.h"
37 #include "rcl/timer.h"
38 
39 #include "rmw/rmw.h"
40 
41 namespace rclcpp
42 {
43 
44 struct TimerInfo
45 {
46  Time expected_call_time;
47  Time actual_call_time;
48 };
49 
50 class TimerBase
51 {
52 public:
53  RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(TimerBase)
54 
55 
65  RCLCPP_PUBLIC
66  explicit TimerBase(
67  Clock::SharedPtr clock,
68  std::chrono::nanoseconds period,
69  rclcpp::Context::SharedPtr context,
70  bool autostart = true);
71 
73  RCLCPP_PUBLIC
74  virtual
75  ~TimerBase();
76 
78 
81  RCLCPP_PUBLIC
82  void
83  cancel();
84 
86 
91  RCLCPP_PUBLIC
92  bool
93  is_canceled();
94 
96 
99  RCLCPP_PUBLIC
100  void
101  reset();
102 
104 
111  RCLCPP_PUBLIC
112  virtual std::shared_ptr<void>
113  call() = 0;
114 
116 
119  RCLCPP_PUBLIC
120  virtual void
121  execute_callback(const std::shared_ptr<void> & data) = 0;
122 
123  RCLCPP_PUBLIC
124  std::shared_ptr<const rcl_timer_t>
125  get_timer_handle();
126 
128 
133  RCLCPP_PUBLIC
134  std::chrono::nanoseconds
136 
138 
139  virtual bool is_steady() = 0;
140 
142 
148  RCLCPP_PUBLIC
149  bool is_ready();
150 
152 
161  RCLCPP_PUBLIC
162  bool
163  exchange_in_use_by_wait_set_state(bool in_use_state);
164 
166 
181  RCLCPP_PUBLIC
182  void
183  set_on_reset_callback(const std::function<void(size_t)> & callback);
184 
186  RCLCPP_PUBLIC
187  void
189 
191  RCLCPP_PUBLIC
192  const Clock::SharedPtr & get_clock() const;
193 
194 protected:
195  std::recursive_mutex callback_mutex_;
196  // Declare callback before timer_handle_, so on destruction
197  // the callback is destroyed last. Otherwise, the rcl timer
198  // callback would point briefly to a destroyed function.
199  // Clearing the callback on timer destructor also makes sure
200  // the rcl callback is cleared before on_reset_callback_.
201  std::function<void(size_t)> on_reset_callback_{nullptr};
202 
203  Clock::SharedPtr clock_;
204  std::shared_ptr<rcl_timer_t> timer_handle_;
205 
206  std::atomic<bool> in_use_by_wait_set_{false};
207 
208  RCLCPP_PUBLIC
209  void
210  set_on_reset_callback(rcl_event_callback_t callback, const void * user_data);
211 };
212 
213 using VoidCallbackType = std::function<void ()>;
214 using TimerCallbackType = std::function<void (TimerBase &)>;
215 using TimerInfoCallbackType = std::function<void (const TimerInfo &)>;
216 
218 template<
219  typename FunctorT,
220  typename std::enable_if<
224  >::type * = nullptr
225 >
226 class GenericTimer : public TimerBase
227 {
228 public:
229  RCLCPP_SMART_PTR_DEFINITIONS(GenericTimer)
230 
231 
239  explicit GenericTimer(
240  Clock::SharedPtr clock, std::chrono::nanoseconds period, FunctorT && callback,
241  rclcpp::Context::SharedPtr context, bool autostart = true
242  )
243  : TimerBase(clock, period, context, autostart), callback_(std::forward<FunctorT>(callback))
244  {
245  TRACETOOLS_TRACEPOINT(
246  rclcpp_timer_callback_added,
247  static_cast<const void *>(get_timer_handle().get()),
248  reinterpret_cast<const void *>(&callback_));
249 #ifndef TRACETOOLS_DISABLED
250  if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
251  char * symbol = tracetools::get_symbol(callback_);
252  TRACETOOLS_DO_TRACEPOINT(
253  rclcpp_callback_register,
254  reinterpret_cast<const void *>(&callback_),
255  symbol);
256  std::free(symbol);
257  }
258 #endif
259  }
260 
262  virtual ~GenericTimer()
263  {
264  // Stop the timer from running.
265  cancel();
266  }
267 
272  std::shared_ptr<void>
273  call() override
274  {
275  auto timer_call_info_ = std::make_shared<rcl_timer_call_info_t>();
276  rcl_ret_t ret = rcl_timer_call_with_info(timer_handle_.get(), timer_call_info_.get());
277  if (ret == RCL_RET_TIMER_CANCELED) {
278  return nullptr;
279  }
280  if (ret != RCL_RET_OK) {
281  throw std::runtime_error("Failed to notify timer that callback occurred");
282  }
283  return timer_call_info_;
284  }
285 
289  void
290  execute_callback(const std::shared_ptr<void> & data) override
291  {
292  TRACETOOLS_TRACEPOINT(callback_start, reinterpret_cast<const void *>(&callback_), false);
293  execute_callback_delegate<>(*static_cast<rcl_timer_call_info_t *>(data.get()));
294  TRACETOOLS_TRACEPOINT(callback_end, reinterpret_cast<const void *>(&callback_));
295  }
296 
297  // void specialization
298  template<
299  typename CallbackT = FunctorT,
300  typename std::enable_if<
302  >::type * = nullptr
303  >
304  void
305  execute_callback_delegate(const rcl_timer_call_info_t &)
306  {
307  callback_();
308  }
309 
310  template<
311  typename CallbackT = FunctorT,
312  typename std::enable_if<
314  >::type * = nullptr
315  >
316  void
317  execute_callback_delegate(const rcl_timer_call_info_t &)
318  {
319  callback_(*this);
320  }
321 
322 
323  template<
324  typename CallbackT = FunctorT,
325  typename std::enable_if<
327  >::type * = nullptr
328  >
329  void
330  execute_callback_delegate(const rcl_timer_call_info_t & timer_call_info)
331  {
332  const TimerInfo info{Time{timer_call_info.expected_call_time, clock_->get_clock_type()},
333  Time{timer_call_info.actual_call_time, clock_->get_clock_type()}};
334  callback_(info);
335  }
336 
338 
339  bool
340  is_steady() override
341  {
342  return clock_->get_clock_type() == RCL_STEADY_TIME;
343  }
344 
345 protected:
346  RCLCPP_DISABLE_COPY(GenericTimer)
347 
348  FunctorT callback_;
349 };
350 
351 template<
352  typename FunctorT,
353  typename std::enable_if<
357  >::type * = nullptr
358 >
359 class WallTimer : public GenericTimer<FunctorT>
360 {
361 public:
362  RCLCPP_SMART_PTR_DEFINITIONS(WallTimer)
363 
364 
372  std::chrono::nanoseconds period,
373  FunctorT && callback,
374  rclcpp::Context::SharedPtr context,
375  bool autostart = true)
376  : GenericTimer<FunctorT>(
377  std::make_shared<Clock>(RCL_STEADY_TIME), period, std::move(callback), context, autostart)
378  {}
379 
380 protected:
381  RCLCPP_DISABLE_COPY(WallTimer)
382 };
383 
384 } // namespace rclcpp
385 
386 #endif // RCLCPP__TIMER_HPP_
Context which encapsulates shared state between nodes and other similar entities.
Definition: context.hpp:80
Generic timer. Periodically executes a user-specified callback.
Definition: timer.hpp:227
bool is_steady() override
Is the clock steady (i.e. is the time between ticks constant?)
Definition: timer.hpp:340
void execute_callback(const std::shared_ptr< void > &data) override
Definition: timer.hpp:290
virtual ~GenericTimer()
Default destructor.
Definition: timer.hpp:262
std::shared_ptr< void > call() override
Definition: timer.hpp:273
virtual RCLCPP_PUBLIC ~TimerBase()
TimerBase destructor.
Definition: timer.cpp:76
RCLCPP_PUBLIC const Clock::SharedPtr & get_clock() const
Returns the clock this timer uses.
Definition: timer.cpp:220
RCLCPP_PUBLIC void set_on_reset_callback(const std::function< void(size_t)> &callback)
Set a callback to be called when the timer is reset.
Definition: timer.cpp:152
RCLCPP_PUBLIC bool is_canceled()
Return the timer cancellation state.
Definition: timer.cpp:91
RCLCPP_PUBLIC void reset()
Reset the timer.
Definition: timer.cpp:102
RCLCPP_PUBLIC void clear_on_reset_callback()
Unset the callback registered for reset timer.
Definition: timer.cpp:201
virtual RCLCPP_PUBLIC void execute_callback(const std::shared_ptr< void > &data)=0
Call the callback function when the timer signal is emitted.
virtual RCLCPP_PUBLIC std::shared_ptr< void > call()=0
Indicate that we're about to execute the callback.
RCLCPP_PUBLIC bool exchange_in_use_by_wait_set_state(bool in_use_state)
Exchange the "in use by wait set" state for this timer.
Definition: timer.cpp:146
virtual bool is_steady()=0
Is the clock steady (i.e. is the time between ticks constant?)
RCLCPP_PUBLIC bool is_ready()
Check if the timer is ready to trigger the callback.
Definition: timer.cpp:115
RCLCPP_PUBLIC TimerBase(Clock::SharedPtr clock, std::chrono::nanoseconds period, rclcpp::Context::SharedPtr context, bool autostart=true)
TimerBase constructor.
Definition: timer.cpp:31
RCLCPP_PUBLIC std::chrono::nanoseconds time_until_trigger()
Check how long the timer has until its next scheduled callback.
Definition: timer.cpp:126
RCLCPP_PUBLIC void cancel()
Cancel the timer.
Definition: timer.cpp:82
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
Structure which encapsulates timer information when called.
Definition: timer.h:56
@ RCL_STEADY_TIME
Use a steady clock time.
Definition: time.h:70
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_call_with_info(rcl_timer_t *timer, rcl_timer_call_info_t *call_info)
Same as rcl_timer_call() except that it also retrieves the actual and expected call time.
Definition: timer.c:245
#define RCL_RET_OK
Success return code.
Definition: types.h:27
#define RCL_RET_TIMER_CANCELED
Given timer was canceled return code.
Definition: types.h:95
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24