ROS 2 rclcpp + rcl - rolling  rolling-e7363f10
ROS 2 C++ Client Library with ROS Client Library
timer.c
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 #ifdef __cplusplus
16 extern "C"
17 {
18 #endif
19 
20 #include "rcl/timer.h"
21 
22 #include <inttypes.h>
23 #include <stdbool.h>
24 #include <stddef.h>
25 
26 #include "rcl/allocator.h"
27 #include "rcl/error_handling.h"
28 #include "rcl/time.h"
29 #include "rcl/types.h"
30 #include "rcutils/logging_macros.h"
31 #include "rcutils/macros.h"
32 #include "rcutils/stdatomic_helper.h"
33 #include "tracetools/tracetools.h"
34 #include "./timer_impl.h"
35 
38 {
39  // All members are initialized to 0 or NULL by C99 6.7.8/10.
40  static rcl_timer_t null_timer;
41  return null_timer;
42 }
43 
44 void _rcl_timer_time_jump(
45  const rcl_time_jump_t * time_jump,
46  bool before_jump,
47  void * user_data)
48 {
49  rcl_timer_impl_t * impl = (rcl_timer_impl_t *)user_data;
50 
51  if (before_jump) {
52  if (RCL_ROS_TIME_ACTIVATED == time_jump->clock_change ||
54  {
56  if (RCL_RET_OK != rcl_clock_get_now(impl->clock, &now)) {
57  RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to get current time in jump callback");
58  return;
59  }
60  // Source of time is changing, but the timer has ellapsed some portion of its period
61  // Save ellapsed duration pre jump so the timer only waits the remainder in the new epoch
62  if (0 == now) {
63  // No time credit if clock is uninitialized
64  return;
65  }
66  const int64_t next_call_time = rcutils_atomic_load_int64_t(&impl->next_call_time);
67  rcutils_atomic_store(&impl->time_credit, next_call_time - now);
68  }
69  } else {
71  if (RCL_RET_OK != rcl_clock_get_now(impl->clock, &now)) {
72  RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to get current time in jump callback");
73  return;
74  }
75  const int64_t last_call_time = rcutils_atomic_load_int64_t(&impl->last_call_time);
76  const int64_t next_call_time = rcutils_atomic_load_int64_t(&impl->next_call_time);
77  const int64_t period = rcutils_atomic_load_int64_t(&impl->period);
78  if (RCL_ROS_TIME_ACTIVATED == time_jump->clock_change ||
80  {
81  // ROS time activated or deactivated
82  if (0 == now) {
83  // Can't apply time credit if clock is uninitialized
84  return;
85  }
86  int64_t time_credit = rcutils_atomic_exchange_int64_t(&impl->time_credit, 0);
87  if (time_credit) {
88  // set times in new epoch so timer only waits the remainder of the period
89  rcutils_atomic_store(&impl->next_call_time, now - time_credit + period);
90  rcutils_atomic_store(&impl->last_call_time, now - time_credit);
91  }
92  } else if (next_call_time <= now) {
93  // Post Forward jump and timer is ready
94  if (RCL_RET_OK != rcl_trigger_guard_condition(&impl->guard_condition)) {
95  RCUTILS_LOG_ERROR_NAMED(
96  ROS_PACKAGE_NAME, "Failed to get trigger guard condition in jump callback");
97  }
98  } else if (now < last_call_time) {
99  // Post backwards time jump that went further back than 1 period
100  // next callback should happen after 1 period
101  rcutils_atomic_store(&impl->next_call_time, now + period);
102  rcutils_atomic_store(&impl->last_call_time, now);
103  return;
104  }
105  }
106 }
107 
108 rcl_ret_t
110  rcl_timer_t * timer,
111  rcl_clock_t * clock,
112  rcl_context_t * context,
113  int64_t period,
114  const rcl_timer_callback_t callback,
115  rcl_allocator_t allocator,
116  bool autostart)
117 {
118  RCL_CHECK_ALLOCATOR_WITH_MSG(&allocator, "invalid allocator", return RCL_RET_INVALID_ARGUMENT);
119  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
120  RCL_CHECK_ARGUMENT_FOR_NULL(clock, RCL_RET_INVALID_ARGUMENT);
121  if (period < 0) {
122  RCL_SET_ERROR_MSG("timer period must be non-negative");
124  }
125  RCUTILS_LOG_DEBUG_NAMED(
126  ROS_PACKAGE_NAME, "Initializing timer with period: %" PRIu64 "ns", period);
127  if (timer->impl) {
128  RCL_SET_ERROR_MSG("timer already initialized, or memory was uninitialized");
129  return RCL_RET_ALREADY_INIT;
130  }
132  rcl_ret_t now_ret = rcl_clock_get_now(clock, &now);
133  if (now_ret != RCL_RET_OK) {
134  RCL_EXPECT_ERROR_IS_SET(now_ret);
135  return now_ret; // rcl error state should already be set.
136  }
137  rcl_timer_impl_t impl;
138  impl.clock = clock;
139  impl.context = context;
140  impl.guard_condition = rcl_get_zero_initialized_guard_condition();
142  rcl_ret_t ret = rcl_guard_condition_init(&(impl.guard_condition), context, options);
143  if (RCL_RET_OK != ret) {
144  return ret;
145  }
146 
147  atomic_init(&impl.callback, (uintptr_t)callback);
148  atomic_init(&impl.callback_data, (uintptr_t)NULL);
149  atomic_init(&impl.period, period);
150  atomic_init(&impl.time_credit, 0);
151  atomic_init(&impl.last_call_time, now);
152  atomic_init(&impl.next_call_time, now + period);
153  atomic_init(&impl.canceled, !autostart);
154  impl.allocator = allocator;
155 
156  // Empty init on reset callback data
157  impl.reset_callback_data.on_reset_callback = NULL;
158  impl.reset_callback_data.user_data = NULL;
159  impl.reset_callback_data.reset_counter = 0;
160  impl.in_use_by_waitset = false;
161 
162  timer->impl = (rcl_timer_impl_t *)allocator.allocate(sizeof(rcl_timer_impl_t), allocator.state);
163  if (NULL == timer->impl) {
164  if (RCL_RET_OK != rcl_guard_condition_fini(&(impl.guard_condition))) {
165  // Should be impossible
166  RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to fini guard condition after bad alloc");
167  }
168  if (RCL_ROS_TIME == impl.clock->type) {
169  if (RCL_RET_OK != rcl_clock_remove_jump_callback(clock, _rcl_timer_time_jump, timer)) {
170  // Should be impossible
171  RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to remove callback after bad alloc");
172  }
173  }
174 
175  RCL_SET_ERROR_MSG("allocating memory failed");
176  return RCL_RET_BAD_ALLOC;
177  }
178  *timer->impl = impl;
179 
180  if (RCL_ROS_TIME == impl.clock->type) {
181  rcl_jump_threshold_t threshold;
182  threshold.on_clock_change = true;
183  threshold.min_forward.nanoseconds = 1;
184  threshold.min_backward.nanoseconds = -1;
185  ret = rcl_clock_add_jump_callback(clock, threshold, _rcl_timer_time_jump, timer->impl);
186  if (RCL_RET_OK != ret) {
187  if (RCL_RET_OK != rcl_guard_condition_fini(&(impl.guard_condition))) {
188  // Should be impossible
189  RCUTILS_LOG_ERROR_NAMED(
190  ROS_PACKAGE_NAME, "Failed to fini guard condition after failing to add jump callback");
191  }
192 
193  allocator.deallocate(timer->impl, allocator.state);
194  timer->impl = NULL;
195 
196  return ret;
197  }
198  }
199 
200  TRACETOOLS_TRACEPOINT(rcl_timer_init, (const void *)timer, period);
201  return RCL_RET_OK;
202 }
203 
204 rcl_ret_t
206 {
207  if (!timer || !timer->impl) {
208  return RCL_RET_OK;
209  }
210  // Will return either RCL_RET_OK or RCL_RET_ERROR since the timer is valid.
211  rcl_ret_t result = rcl_timer_cancel(timer);
212  rcl_allocator_t allocator = timer->impl->allocator;
213  rcl_ret_t fail_ret;
214  if (RCL_ROS_TIME == timer->impl->clock->type) {
215  // The jump callbacks use the guard condition, so we have to remove it
216  // before freeing the guard condition below.
217  fail_ret = rcl_clock_remove_jump_callback(timer->impl->clock, _rcl_timer_time_jump,
218  timer->impl);
219  if (RCL_RET_OK != fail_ret) {
220  RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to remove timer jump callback");
221  }
222  }
223  fail_ret = rcl_guard_condition_fini(&(timer->impl->guard_condition));
224  if (RCL_RET_OK != fail_ret) {
225  RCL_SET_ERROR_MSG("Failure to fini guard condition");
226  }
227  allocator.deallocate(timer->impl, allocator.state);
228  timer->impl = NULL;
229  return result;
230 }
231 
232 rcl_ret_t
233 rcl_timer_clock(const rcl_timer_t * timer, rcl_clock_t ** clock)
234 {
235  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
236  RCL_CHECK_ARGUMENT_FOR_NULL(clock, RCL_RET_INVALID_ARGUMENT);
237  RCL_CHECK_ARGUMENT_FOR_NULL(timer->impl, RCL_RET_TIMER_INVALID);
238  *clock = timer->impl->clock;
239  return RCL_RET_OK;
240 }
241 
242 rcl_ret_t
244 {
246  return rcl_timer_call_with_info(timer, &info);
247 }
248 
249 rcl_ret_t
251 {
252  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Calling timer");
253  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
254  RCL_CHECK_ARGUMENT_FOR_NULL(timer->impl, RCL_RET_TIMER_INVALID);
255  RCL_CHECK_ARGUMENT_FOR_NULL(call_info, RCL_RET_INVALID_ARGUMENT);
256  if (rcutils_atomic_load_bool(&timer->impl->canceled)) {
257  RCL_SET_ERROR_MSG("timer is canceled");
258  return RCL_RET_TIMER_CANCELED;
259  }
261  rcl_ret_t now_ret = rcl_clock_get_now(timer->impl->clock, &now);
262  if (now_ret != RCL_RET_OK) {
263  RCL_EXPECT_ERROR_IS_SET(now_ret);
264  return now_ret; // rcl error state should already be set.
265  }
266  if (now < 0) {
267  RCL_SET_ERROR_MSG("clock now returned negative time point value");
268  return RCL_RET_ERROR;
269  }
270  rcl_time_point_value_t previous_ns =
271  rcutils_atomic_exchange_int64_t(&timer->impl->last_call_time, now);
272  rcl_timer_callback_t typed_callback =
273  (rcl_timer_callback_t)rcutils_atomic_load_uintptr_t(&timer->impl->callback);
274 
275  int64_t next_call_time = rcutils_atomic_load_int64_t(&timer->impl->next_call_time);
276  call_info->expected_call_time = next_call_time;
277  call_info->actual_call_time = now;
278  int64_t period = rcutils_atomic_load_int64_t(&timer->impl->period);
279  // always move the next call time by exactly period forward
280  // don't use now as the base to avoid extending each cycle by the time
281  // between the timer being ready and the callback being triggered
282  next_call_time += period;
283  // in case the timer has missed at least once cycle
284  if (next_call_time <= now) {
285  if (0 == period) {
286  // a timer with a period of zero is considered always ready
287  next_call_time = now;
288  } else {
289  // move the next call time forward by as many periods as necessary
290  int64_t now_ahead = now - next_call_time;
291  // rounding up without overflow
292  int64_t periods_ahead = 1 + now_ahead / period;
293  next_call_time += periods_ahead * period;
294  }
295  }
296  rcutils_atomic_store(&timer->impl->next_call_time, next_call_time);
297 
298  if (typed_callback != NULL) {
299  int64_t since_last_call = now - previous_ns;
300  uintptr_t callback_data = rcl_timer_get_callback_data(timer);
301  typed_callback(timer, since_last_call, callback_data);
302  }
303  return RCL_RET_OK;
304 }
305 
306 rcl_ret_t
307 rcl_timer_is_ready(const rcl_timer_t * timer, bool * is_ready)
308 {
309  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
310  RCL_CHECK_ARGUMENT_FOR_NULL(timer->impl, RCL_RET_TIMER_INVALID);
311  RCL_CHECK_ARGUMENT_FOR_NULL(is_ready, RCL_RET_INVALID_ARGUMENT);
312  int64_t time_until_next_call;
313  rcl_ret_t ret = rcl_timer_get_time_until_next_call(timer, &time_until_next_call);
314  if (ret == RCL_RET_TIMER_CANCELED) {
315  *is_ready = false;
316  return RCL_RET_OK;
317  } else if (ret != RCL_RET_OK) {
318  RCL_EXPECT_ERROR_IS_SET(ret);
319  return ret; // rcl error state should already be set.
320  }
321  *is_ready = (time_until_next_call <= 0);
322  return RCL_RET_OK;
323 }
324 
325 rcl_ret_t
326 rcl_timer_get_next_call_time(const rcl_timer_t * timer, int64_t * next_call_time)
327 {
328  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
329  RCL_CHECK_ARGUMENT_FOR_NULL(timer->impl, RCL_RET_TIMER_INVALID);
330  RCL_CHECK_ARGUMENT_FOR_NULL(next_call_time, RCL_RET_INVALID_ARGUMENT);
331 
332  if (rcutils_atomic_load_bool(&timer->impl->canceled)) {
333  return RCL_RET_TIMER_CANCELED;
334  }
335 
336  *next_call_time =
337  rcutils_atomic_load_int64_t(&timer->impl->next_call_time);
338  return RCL_RET_OK;
339 }
340 
341 rcl_ret_t
342 rcl_timer_get_time_until_next_call(const rcl_timer_t * timer, int64_t * time_until_next_call)
343 {
344  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
345  RCL_CHECK_ARGUMENT_FOR_NULL(timer->impl, RCL_RET_TIMER_INVALID);
346  RCL_CHECK_ARGUMENT_FOR_NULL(time_until_next_call, RCL_RET_INVALID_ARGUMENT);
347  if (rcutils_atomic_load_bool(&timer->impl->canceled)) {
348  return RCL_RET_TIMER_CANCELED;
349  }
351  rcl_ret_t ret = rcl_clock_get_now(timer->impl->clock, &now);
352  if (ret != RCL_RET_OK) {
353  RCL_EXPECT_ERROR_IS_SET(ret);
354  return ret; // rcl error state should already be set.
355  }
356  *time_until_next_call =
357  rcutils_atomic_load_int64_t(&timer->impl->next_call_time) - now;
358  return RCL_RET_OK;
359 }
360 
361 rcl_ret_t
363  const rcl_timer_t * timer,
364  rcl_time_point_value_t * time_since_last_call)
365 {
366  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
367  RCL_CHECK_ARGUMENT_FOR_NULL(timer->impl, RCL_RET_TIMER_INVALID);
368  RCL_CHECK_ARGUMENT_FOR_NULL(time_since_last_call, RCL_RET_INVALID_ARGUMENT);
370  rcl_ret_t ret = rcl_clock_get_now(timer->impl->clock, &now);
371  if (ret != RCL_RET_OK) {
372  RCL_EXPECT_ERROR_IS_SET(ret);
373  return ret; // rcl error state should already be set.
374  }
375  *time_since_last_call =
376  now - rcutils_atomic_load_int64_t(&timer->impl->last_call_time);
377  return RCL_RET_OK;
378 }
379 
380 rcl_ret_t
381 rcl_timer_get_period(const rcl_timer_t * timer, int64_t * period)
382 {
383  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
384  RCL_CHECK_ARGUMENT_FOR_NULL(timer->impl, RCL_RET_TIMER_INVALID);
385  RCL_CHECK_ARGUMENT_FOR_NULL(period, RCL_RET_INVALID_ARGUMENT);
386  *period = rcutils_atomic_load_int64_t(&timer->impl->period);
387  return RCL_RET_OK;
388 }
389 
390 rcl_ret_t
391 rcl_timer_exchange_period(const rcl_timer_t * timer, int64_t new_period, int64_t * old_period)
392 {
393  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
394 
395  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
396  RCL_CHECK_ARGUMENT_FOR_NULL(timer->impl, RCL_RET_TIMER_INVALID);
397  RCL_CHECK_ARGUMENT_FOR_NULL(old_period, RCL_RET_INVALID_ARGUMENT);
398  *old_period = rcutils_atomic_exchange_int64_t(&timer->impl->period, new_period);
399  RCUTILS_LOG_DEBUG_NAMED(
400  ROS_PACKAGE_NAME, "Updated timer period from '%" PRIu64 "ns' to '%" PRIu64 "ns'",
401  *old_period, new_period);
402  return RCL_RET_OK;
403 }
404 
407 {
408  RCL_CHECK_ARGUMENT_FOR_NULL(timer, NULL);
409  RCL_CHECK_FOR_NULL_WITH_MSG(timer->impl, "timer is invalid", return NULL);
410  return (rcl_timer_callback_t)rcutils_atomic_load_uintptr_t(&timer->impl->callback);
411 }
412 
413 uintptr_t
415 {
416  RCL_CHECK_ARGUMENT_FOR_NULL(timer, (uintptr_t)NULL);
417  RCL_CHECK_FOR_NULL_WITH_MSG(timer->impl, "timer is invalid", return (uintptr_t)NULL);
418  return (uintptr_t)rcutils_atomic_load_uintptr_t(&timer->impl->callback_data);
419 }
420 
423 {
424  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Updating timer callback");
425  RCL_CHECK_ARGUMENT_FOR_NULL(timer, NULL);
426  RCL_CHECK_FOR_NULL_WITH_MSG(timer->impl, "timer is invalid", return NULL);
427  return (rcl_timer_callback_t)rcutils_atomic_exchange_uintptr_t(
428  &timer->impl->callback, (uintptr_t)new_callback);
429 }
430 
431 uintptr_t
433 {
434  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
435  RCL_CHECK_FOR_NULL_WITH_MSG(timer->impl, "timer is invalid", return RCL_RET_TIMER_INVALID);
436 
437  return rcutils_atomic_exchange_uintptr_t(&timer->impl->callback_data, data);
438 }
439 
440 rcl_ret_t
442 {
443  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
444  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_TIMER_INVALID);
445 
446  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
447  RCL_CHECK_FOR_NULL_WITH_MSG(timer->impl, "timer is invalid", return RCL_RET_TIMER_INVALID);
448  rcutils_atomic_store(&timer->impl->canceled, true);
449  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Timer canceled");
450  return RCL_RET_OK;
451 }
452 
453 rcl_ret_t
454 rcl_timer_is_canceled(const rcl_timer_t * timer, bool * is_canceled)
455 {
456  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
457  RCL_CHECK_ARGUMENT_FOR_NULL(timer->impl, RCL_RET_TIMER_INVALID);
458  RCL_CHECK_ARGUMENT_FOR_NULL(is_canceled, RCL_RET_INVALID_ARGUMENT);
459  *is_canceled = rcutils_atomic_load_bool(&timer->impl->canceled);
460  return RCL_RET_OK;
461 }
462 
463 rcl_ret_t
465 {
466  RCUTILS_CAN_RETURN_WITH_ERROR_OF(RCL_RET_INVALID_ARGUMENT);
467 
468  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
469  RCL_CHECK_FOR_NULL_WITH_MSG(timer->impl, "timer is invalid", return RCL_RET_TIMER_INVALID);
471  rcl_ret_t now_ret = rcl_clock_get_now(timer->impl->clock, &now);
472  if (now_ret != RCL_RET_OK) {
473  RCL_EXPECT_ERROR_IS_SET(now_ret);
474  return now_ret; // rcl error state should already be set.
475  }
476  int64_t period = rcutils_atomic_load_int64_t(&timer->impl->period);
477  rcutils_atomic_store(&timer->impl->next_call_time, now + period);
478  rcutils_atomic_store(&timer->impl->canceled, false);
479  rcl_ret_t ret = rcl_trigger_guard_condition(&timer->impl->guard_condition);
480 
481  rcl_timer_on_reset_callback_data_t * cb_data = &timer->impl->reset_callback_data;
482 
483  if (cb_data->on_reset_callback) {
484  cb_data->on_reset_callback(cb_data->user_data, 1);
485  } else {
486  cb_data->reset_counter++;
487  }
488 
489  if (ret != RCL_RET_OK) {
490  RCUTILS_LOG_ERROR_NAMED(ROS_PACKAGE_NAME, "Failed to trigger timer guard condition");
491  }
492  RCUTILS_LOG_DEBUG_NAMED(ROS_PACKAGE_NAME, "Timer successfully reset");
493  return RCL_RET_OK;
494 }
495 
496 const rcl_allocator_t *
498 {
499  RCL_CHECK_ARGUMENT_FOR_NULL(timer, NULL);
500  RCL_CHECK_FOR_NULL_WITH_MSG(timer->impl, "timer is invalid", return NULL);
501  return &timer->impl->allocator;
502 }
503 
506 {
507  if (NULL == timer || NULL == timer->impl || NULL == timer->impl->guard_condition.impl) {
508  return NULL;
509  }
510  return &timer->impl->guard_condition;
511 }
512 
513 rcl_ret_t
515  const rcl_timer_t * timer,
516  rcl_event_callback_t on_reset_callback,
517  const void * user_data)
518 {
519  RCL_CHECK_ARGUMENT_FOR_NULL(timer, RCL_RET_INVALID_ARGUMENT);
520 
521  rcl_timer_on_reset_callback_data_t * cb_data = &timer->impl->reset_callback_data;
522 
523  if (on_reset_callback) {
524  cb_data->on_reset_callback = on_reset_callback;
525  cb_data->user_data = user_data;
526  if (cb_data->reset_counter) {
527  cb_data->on_reset_callback(user_data, cb_data->reset_counter);
528  cb_data->reset_counter = 0;
529  }
530  } else {
531  cb_data->on_reset_callback = NULL;
532  cb_data->user_data = NULL;
533  }
534 
535  return RCL_RET_OK;
536 }
537 
538 #ifdef __cplusplus
539 }
540 #endif
#define RCL_CHECK_ALLOCATOR_WITH_MSG(allocator, msg, fail_statement)
Check that the given allocator is initialized, or fail with a message.
Definition: allocator.h:56
rcutils_allocator_t rcl_allocator_t
Encapsulation of an allocator.
Definition: allocator.h:31
RCL_PUBLIC RCL_WARN_UNUSED rcl_guard_condition_t rcl_get_zero_initialized_guard_condition(void)
Return a rcl_guard_condition_t struct with members set to NULL.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_trigger_guard_condition(rcl_guard_condition_t *guard_condition)
Trigger a rcl guard condition.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_guard_condition_init(rcl_guard_condition_t *guard_condition, rcl_context_t *context, const rcl_guard_condition_options_t options)
Initialize a rcl guard_condition.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_guard_condition_fini(rcl_guard_condition_t *guard_condition)
Finalize a rcl_guard_condition_t.
RCL_PUBLIC RCL_WARN_UNUSED rcl_guard_condition_options_t rcl_guard_condition_get_default_options(void)
Return the default options in a rcl_guard_condition_options_t struct.
Encapsulation of a time source.
Definition: time.h:141
rcl_clock_type_t type
Clock type.
Definition: time.h:143
Encapsulates the non-global state of an init/shutdown cycle.
Definition: context.h:117
rcl_duration_value_t nanoseconds
Duration in nanoseconds and its source.
Definition: time.h:80
Options available for a rcl guard condition.
Handle for a rcl guard condition.
rcl_guard_condition_impl_t * impl
Pointer to the guard condition implementation.
Describe the prerequisites for calling a time jump callback.
Definition: time.h:117
rcl_duration_t min_forward
Definition: time.h:122
bool on_clock_change
True to call callback when the clock type changes.
Definition: time.h:119
rcl_duration_t min_backward
Definition: time.h:125
Struct to describe a jump in time.
Definition: time.h:98
rcl_clock_change_t clock_change
Indicate whether or not the source of time changed.
Definition: time.h:100
Structure which encapsulates timer information when called.
Definition: timer.h:57
Structure which encapsulates the on reset callback data.
Definition: timer.h:49
Structure which encapsulates a ROS Timer.
Definition: timer.h:42
rcl_timer_impl_t * impl
Private implementation pointer.
Definition: timer.h:44
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_clock_get_now(rcl_clock_t *clock, rcl_time_point_value_t *time_point_value)
Fill the time point value with the current value of the associated clock.
Definition: time.c:263
@ RCL_ROS_TIME_DEACTIVATED
The source switched to SYSTEM_TIME from ROS_TIME.
Definition: time.h:91
@ RCL_ROS_TIME_ACTIVATED
The source switched to ROS_TIME from SYSTEM_TIME.
Definition: time.h:89
rcutils_time_point_value_t rcl_time_point_value_t
A single point in time, measured in nanoseconds since the Unix epoch.
Definition: time.h:49
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_clock_add_jump_callback(rcl_clock_t *clock, rcl_jump_threshold_t threshold, rcl_jump_callback_t callback, void *user_data)
Add a callback to be called when a time jump exceeds a threshold.
Definition: time.c:392
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_clock_remove_jump_callback(rcl_clock_t *clock, rcl_jump_callback_t callback, void *user_data)
Remove a previously added time jump callback.
Definition: time.c:436
@ RCL_ROS_TIME
Use ROS time.
Definition: time.h:69
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_get_next_call_time(const rcl_timer_t *timer, int64_t *next_call_time)
Retrieve the time when the next call to rcl_timer_call() shall occur.
Definition: timer.c:326
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_get_time_since_last_call(const rcl_timer_t *timer, int64_t *time_since_last_call)
Retrieve the time since the previous call to rcl_timer_call() occurred.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_get_time_until_next_call(const rcl_timer_t *timer, int64_t *time_until_next_call)
Calculate and retrieve the time until the next call in nanoseconds.
Definition: timer.c:342
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_call(rcl_timer_t *timer)
Call the timer's callback and set the last call time.
Definition: timer.c:243
void(* rcl_timer_callback_t)(rcl_timer_t *, int64_t, uintptr_t)
User callback signature for timers.
Definition: timer.h:77
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_reset(rcl_timer_t *timer)
Reset a timer.
Definition: timer.c:464
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_get_period(const rcl_timer_t *timer, int64_t *period)
Retrieve the period of the timer.
Definition: timer.c:381
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_set_on_reset_callback(const rcl_timer_t *timer, rcl_event_callback_t on_reset_callback, const void *user_data)
Set the on reset callback function for the timer.
Definition: timer.c:514
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_exchange_period(const rcl_timer_t *timer, int64_t new_period, int64_t *old_period)
Exchange the period of the timer and return the previous period.
Definition: timer.c:391
RCL_PUBLIC RCL_WARN_UNUSED rcl_timer_callback_t rcl_timer_get_callback(const rcl_timer_t *timer)
Return the current timer callback.
Definition: timer.c:406
RCL_PUBLIC RCL_WARN_UNUSED rcl_timer_callback_t rcl_timer_exchange_callback(rcl_timer_t *timer, const rcl_timer_callback_t new_callback)
Exchange the current timer callback and return the current callback.
Definition: timer.c:422
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_init2(rcl_timer_t *timer, rcl_clock_t *clock, rcl_context_t *context, int64_t period, const rcl_timer_callback_t callback, rcl_allocator_t allocator, bool autostart)
Initialize a timer.
Definition: timer.c:109
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_cancel(rcl_timer_t *timer)
Cancel a timer.
Definition: timer.c:441
RCL_PUBLIC RCL_WARN_UNUSED uintptr_t rcl_timer_get_callback_data(const rcl_timer_t *timer)
Return the current timer callback data.
Definition: timer.c:414
RCL_PUBLIC RCL_WARN_UNUSED rcl_guard_condition_t * rcl_timer_get_guard_condition(const rcl_timer_t *timer)
Retrieve a guard condition used by the timer to wake the waitset when using ROSTime.
Definition: timer.c:505
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_clock(const rcl_timer_t *timer, rcl_clock_t **clock)
Retrieve the clock of the timer.
Definition: timer.c:233
RCL_PUBLIC RCL_WARN_UNUSED uintptr_t rcl_timer_exchange_callback_data(rcl_timer_t *timer, uintptr_t data)
Set the type erased data that the timer callback will be called with.
Definition: timer.c:432
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:250
RCL_PUBLIC RCL_WARN_UNUSED rcl_timer_t rcl_get_zero_initialized_timer(void)
Return a zero initialized timer.
Definition: timer.c:37
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_fini(rcl_timer_t *timer)
Finalize a timer.
Definition: timer.c:205
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_is_canceled(const rcl_timer_t *timer, bool *is_canceled)
Retrieve the canceled state of a timer.
Definition: timer.c:454
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_timer_is_ready(const rcl_timer_t *timer, bool *is_ready)
Calculates whether or not the timer should be called.
Definition: timer.c:307
RCL_PUBLIC RCL_WARN_UNUSED const rcl_allocator_t * rcl_timer_get_allocator(const rcl_timer_t *timer)
Return the allocator for the timer.
Definition: timer.c:497
#define RCL_RET_TIMER_INVALID
Invalid rcl_timer_t given return code.
Definition: types.h:94
#define RCL_RET_ALREADY_INIT
rcl_init() already called return code.
Definition: types.h:42
#define RCL_RET_OK
Success return code.
Definition: types.h:28
#define RCL_RET_BAD_ALLOC
Failed to allocate memory return code.
Definition: types.h:34
#define RCL_RET_INVALID_ARGUMENT
Invalid argument return code.
Definition: types.h:36
#define RCL_RET_ERROR
Unspecified error return code.
Definition: types.h:30
#define RCL_RET_TIMER_CANCELED
Given timer was canceled return code.
Definition: types.h:96
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:25