ROS 2 rclcpp + rcl - rolling  rolling-20536064
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 <sstream>
24 #include <thread>
25 #include <type_traits>
26 #include <utility>
27 
28 #include "rclcpp/clock.hpp"
29 #include "rclcpp/context.hpp"
30 #include "rclcpp/function_traits.hpp"
31 #include "rclcpp/macros.hpp"
32 #include "rclcpp/utilities.hpp"
33 #include "rclcpp/visibility_control.hpp"
34 #include "tracetools/tracetools.h"
35 #include "tracetools/utils.hpp"
36 
37 #include "rcl/error_handling.h"
38 #include "rcl/timer.h"
39 
40 #include "rmw/rmw.h"
41 
42 namespace rclcpp
43 {
44 
45 struct TimerInfo
46 {
47  Time expected_call_time;
48  Time actual_call_time;
49 };
50 
51 class TimerBase
52 {
53 public:
54  RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(TimerBase)
55 
56 
66  RCLCPP_PUBLIC
67  explicit TimerBase(
68  Clock::SharedPtr clock,
69  std::chrono::nanoseconds period,
70  rclcpp::Context::SharedPtr context,
71  bool autostart = true);
72 
74  RCLCPP_PUBLIC
75  virtual
76  ~TimerBase();
77 
79 
82  RCLCPP_PUBLIC
83  void
84  cancel();
85 
87 
92  RCLCPP_PUBLIC
93  bool
94  is_canceled();
95 
97 
100  RCLCPP_PUBLIC
101  void
102  reset();
103 
105 
112  RCLCPP_PUBLIC
113  virtual std::shared_ptr<void>
114  call() = 0;
115 
117 
120  RCLCPP_PUBLIC
121  virtual void
122  execute_callback(const std::shared_ptr<void> & data) = 0;
123 
124  RCLCPP_PUBLIC
125  std::shared_ptr<const rcl_timer_t>
126  get_timer_handle();
127 
129 
134  RCLCPP_PUBLIC
135  std::chrono::nanoseconds
137 
139 
140  virtual bool is_steady() = 0;
141 
143 
149  RCLCPP_PUBLIC
150  bool is_ready();
151 
153 
162  RCLCPP_PUBLIC
163  bool
164  exchange_in_use_by_wait_set_state(bool in_use_state);
165 
167 
182  RCLCPP_PUBLIC
183  void
184  set_on_reset_callback(const std::function<void(size_t)> & callback);
185 
187  RCLCPP_PUBLIC
188  void
190 
192  RCLCPP_PUBLIC
193  const Clock::SharedPtr & get_clock() const;
194 
195 protected:
196  std::recursive_mutex callback_mutex_;
197  // Declare callback before timer_handle_, so on destruction
198  // the callback is destroyed last. Otherwise, the rcl timer
199  // callback would point briefly to a destroyed function.
200  // Clearing the callback on timer destructor also makes sure
201  // the rcl callback is cleared before on_reset_callback_.
202  std::function<void(size_t)> on_reset_callback_{nullptr};
203 
204  Clock::SharedPtr clock_;
205  std::shared_ptr<rcl_timer_t> timer_handle_;
206 
207  std::atomic<bool> in_use_by_wait_set_{false};
208 
209  RCLCPP_PUBLIC
210  void
211  set_on_reset_callback(rcl_event_callback_t callback, const void * user_data);
212 };
213 
214 using VoidCallbackType = std::function<void ()>;
215 using TimerCallbackType = std::function<void (TimerBase &)>;
216 using TimerInfoCallbackType = std::function<void (const TimerInfo &)>;
217 
219 template<
220  typename FunctorT,
221  typename std::enable_if<
225  >::type * = nullptr
226 >
227 class GenericTimer : public TimerBase
228 {
229 public:
230  RCLCPP_SMART_PTR_DEFINITIONS(GenericTimer)
231 
232 
240  explicit GenericTimer(
241  Clock::SharedPtr clock, std::chrono::nanoseconds period, FunctorT && callback,
242  rclcpp::Context::SharedPtr context, bool autostart = true
243  )
244  : TimerBase(clock, period, context, autostart), callback_(std::forward<FunctorT>(callback))
245  {
246  TRACETOOLS_TRACEPOINT(
247  rclcpp_timer_callback_added,
248  static_cast<const void *>(get_timer_handle().get()),
249  reinterpret_cast<const void *>(&callback_));
250 #ifndef TRACETOOLS_DISABLED
251  if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
252  char * symbol = tracetools::get_symbol(callback_);
253  TRACETOOLS_DO_TRACEPOINT(
254  rclcpp_callback_register,
255  reinterpret_cast<const void *>(&callback_),
256  symbol);
257  std::free(symbol);
258  }
259 #endif
260  }
261 
263  virtual ~GenericTimer()
264  {
265  // Stop the timer from running.
266  cancel();
267  }
268 
273  std::shared_ptr<void>
274  call() override
275  {
276  auto timer_call_info_ = std::make_shared<rcl_timer_call_info_t>();
277  rcl_ret_t ret = rcl_timer_call_with_info(timer_handle_.get(), timer_call_info_.get());
278  if (ret == RCL_RET_TIMER_CANCELED) {
279  return nullptr;
280  }
281  if (ret != RCL_RET_OK) {
282  throw std::runtime_error("Failed to notify timer that callback occurred");
283  }
284  return timer_call_info_;
285  }
286 
290  void
291  execute_callback(const std::shared_ptr<void> & data) override
292  {
293  TRACETOOLS_TRACEPOINT(callback_start, reinterpret_cast<const void *>(&callback_), false);
294  execute_callback_delegate<>(*static_cast<rcl_timer_call_info_t *>(data.get()));
295  TRACETOOLS_TRACEPOINT(callback_end, reinterpret_cast<const void *>(&callback_));
296  }
297 
298  // void specialization
299  template<
300  typename CallbackT = FunctorT,
301  typename std::enable_if<
303  >::type * = nullptr
304  >
305  void
306  execute_callback_delegate(const rcl_timer_call_info_t &)
307  {
308  callback_();
309  }
310 
311  template<
312  typename CallbackT = FunctorT,
313  typename std::enable_if<
315  >::type * = nullptr
316  >
317  void
318  execute_callback_delegate(const rcl_timer_call_info_t &)
319  {
320  callback_(*this);
321  }
322 
323 
324  template<
325  typename CallbackT = FunctorT,
326  typename std::enable_if<
328  >::type * = nullptr
329  >
330  void
331  execute_callback_delegate(const rcl_timer_call_info_t & timer_call_info)
332  {
333  const TimerInfo info{Time{timer_call_info.expected_call_time, clock_->get_clock_type()},
334  Time{timer_call_info.actual_call_time, clock_->get_clock_type()}};
335  callback_(info);
336  }
337 
339 
340  bool
341  is_steady() override
342  {
343  return clock_->get_clock_type() == RCL_STEADY_TIME;
344  }
345 
346 protected:
347  RCLCPP_DISABLE_COPY(GenericTimer)
348 
349  FunctorT callback_;
350 };
351 
352 template<
353  typename FunctorT,
354  typename std::enable_if<
358  >::type * = nullptr
359 >
360 class WallTimer : public GenericTimer<FunctorT>
361 {
362 public:
363  RCLCPP_SMART_PTR_DEFINITIONS(WallTimer)
364 
365 
373  std::chrono::nanoseconds period,
374  FunctorT && callback,
375  rclcpp::Context::SharedPtr context,
376  bool autostart = true)
377  : GenericTimer<FunctorT>(
378  std::make_shared<Clock>(RCL_STEADY_TIME), period, std::move(callback), context, autostart)
379  {}
380 
381 protected:
382  RCLCPP_DISABLE_COPY(WallTimer)
383 };
384 
385 } // namespace rclcpp
386 
387 #endif // RCLCPP__TIMER_HPP_
Context which encapsulates shared state between nodes and other similar entities.
Definition: context.hpp:79
Generic timer. Periodically executes a user-specified callback.
Definition: timer.hpp:228
bool is_steady() override
Is the clock steady (i.e. is the time between ticks constant?)
Definition: timer.hpp:341
void execute_callback(const std::shared_ptr< void > &data) override
Definition: timer.hpp:291
virtual ~GenericTimer()
Default destructor.
Definition: timer.hpp:263
std::shared_ptr< void > call() override
Definition: timer.hpp:274
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