Skip to content

Commit 885e12a

Browse files
committed
Add new rcutils_raw_steady_time_now method changes
1 parent b4e6e14 commit 885e12a

File tree

4 files changed

+161
-8
lines changed

4 files changed

+161
-8
lines changed

rcl/include/rcl/time.h

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ typedef rcutils_duration_value_t rcl_duration_value_t;
5757
* RCL_SYSTEM_TIME reports the same value as the system clock.
5858
*
5959
* RCL_STEADY_TIME reports a value from a monotonically increasing clock.
60+
*
61+
* RCL_RAW_STEADY_TIME reports a value from a monotonic clock that is not
62+
* adjusted for time jumps, such as those caused by NTP synchronization.
63+
* This clock is not suitable for measuring elapsed time, but can be used to
64+
* measure time intervals without being affected by system time changes.
6065
*/
6166
typedef enum rcl_clock_type_e
6267
{
@@ -67,7 +72,9 @@ typedef enum rcl_clock_type_e
6772
/// Use system time
6873
RCL_SYSTEM_TIME,
6974
/// Use a steady clock time
70-
RCL_STEADY_TIME
75+
RCL_STEADY_TIME,
76+
/// Use a monotonic slew-free steady clock time
77+
RCL_RAW_STEADY_TIME
7178
} rcl_clock_type_t;
7279

7380
/// A duration of time, measured in nanoseconds and its source.
@@ -406,6 +413,69 @@ rcl_ret_t
406413
rcl_steady_clock_fini(
407414
rcl_clock_t * clock);
408415

416+
/// Initialize a clock as a #RCL_RAW_STEADY_TIME time source.
417+
/**
418+
* This will allocate all necessary internal structures, and initialize variables.
419+
* It is specifically setting up a #RCL_RAW_STEADY_TIME time source.
420+
*
421+
* <hr>
422+
* Attribute | Adherence
423+
* ------------------ | -------------
424+
* Allocates Memory | No
425+
* Thread-Safe | No [1]
426+
* Uses Atomics | No
427+
* Lock-Free | Yes
428+
*
429+
* <i>[1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
430+
* Thread-safety is also affected by that of the `allocator` object.</i>
431+
*
432+
* \param[in] clock the handle to the clock which is being initialized
433+
* \param[in] allocator The allocator to use for allocations
434+
* \return #RCL_RET_OK if the time source was successfully initialized, or
435+
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
436+
* \return #RCL_RET_ERROR an unspecified error occur.
437+
*/
438+
RCL_PUBLIC
439+
RCL_WARN_UNUSED
440+
rcl_ret_t
441+
rcl_raw_steady_clock_init(
442+
rcl_clock_t * clock,
443+
rcl_allocator_t * allocator);
444+
445+
/// Finalize a clock as a #RCL_RAW_STEADY_TIME time source.
446+
/**
447+
* Finalize the clock as a #RCL_RAW_STEADY_TIME time source.
448+
*
449+
* This will deallocate all necessary internal structures, and clean up any variables.
450+
* It is specifically setting up a steady time source. It is expected to be
451+
* paired with the init fuction.
452+
*
453+
* This function is not thread-safe with any other function operating on the same
454+
* clock object.
455+
*
456+
* <hr>
457+
* Attribute | Adherence
458+
* ------------------ | -------------
459+
* Allocates Memory | No
460+
* Thread-Safe | No [1]
461+
* Uses Atomics | No
462+
* Lock-Free | Yes
463+
*
464+
* <i>[1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
465+
* Thread-safety is also affected by that of the `allocator` object associated with the
466+
* `clock` object.</i>
467+
*
468+
* \param[in] clock the handle to the clock which is being initialized
469+
* \return #RCL_RET_OK if the time source was successfully finalized, or
470+
* \return #RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
471+
* \return #RCL_RET_ERROR an unspecified error occur.
472+
*/
473+
RCL_PUBLIC
474+
RCL_WARN_UNUSED
475+
rcl_ret_t
476+
rcl_raw_steady_clock_fini(
477+
rcl_clock_t * clock);
478+
409479
/// Initialize a clock as a #RCL_SYSTEM_TIME time source.
410480
/**
411481
* Initialize the clock as a #RCL_SYSTEM_TIME time source.

rcl/src/rcl/time.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ rcl_get_steady_time(void * data, rcl_time_point_value_t * current_time)
3939
return rcutils_steady_time_now(current_time);
4040
}
4141

42+
// Implementation only
43+
static rcl_ret_t
44+
rcl_get_raw_steady_time(void * data, rcl_time_point_value_t * current_time)
45+
{
46+
(void)data; // unused
47+
return rcutils_raw_steady_time_now(current_time);
48+
}
49+
4250
// Implementation only
4351
static rcl_ret_t
4452
rcl_get_system_time(void * data, rcl_time_point_value_t * current_time)
@@ -111,6 +119,8 @@ rcl_clock_init(
111119
return rcl_system_clock_init(clock, allocator);
112120
case RCL_STEADY_TIME:
113121
return rcl_steady_clock_init(clock, allocator);
122+
case RCL_RAW_STEADY_TIME:
123+
return rcl_raw_steady_clock_init(clock, allocator);
114124
default:
115125
return RCL_RET_INVALID_ARGUMENT;
116126
}
@@ -142,6 +152,8 @@ rcl_clock_fini(
142152
return rcl_system_clock_fini(clock);
143153
case RCL_STEADY_TIME:
144154
return rcl_steady_clock_fini(clock);
155+
case RCL_RAW_STEADY_TIME:
156+
return rcl_raw_steady_clock_fini(clock);
145157
case RCL_CLOCK_UNINITIALIZED:
146158
// fall through
147159
default:
@@ -213,6 +225,32 @@ rcl_steady_clock_fini(
213225
return RCL_RET_OK;
214226
}
215227

228+
rcl_ret_t
229+
rcl_raw_steady_clock_init(
230+
rcl_clock_t * clock,
231+
rcl_allocator_t * allocator)
232+
{
233+
RCL_CHECK_ARGUMENT_FOR_NULL(clock, RCL_RET_INVALID_ARGUMENT);
234+
RCL_CHECK_ARGUMENT_FOR_NULL(allocator, RCL_RET_INVALID_ARGUMENT);
235+
rcl_init_generic_clock(clock, allocator);
236+
clock->get_now = rcl_get_raw_steady_time;
237+
clock->type = RCL_RAW_STEADY_TIME;
238+
return RCL_RET_OK;
239+
}
240+
241+
rcl_ret_t
242+
rcl_raw_steady_clock_fini(
243+
rcl_clock_t * clock)
244+
{
245+
RCL_CHECK_ARGUMENT_FOR_NULL(clock, RCL_RET_INVALID_ARGUMENT);
246+
if (clock->type != RCL_RAW_STEADY_TIME) {
247+
RCL_SET_ERROR_MSG("clock not of type RCL_RAW_STEADY_TIME");
248+
return RCL_RET_ERROR;
249+
}
250+
rcl_clock_generic_fini(clock);
251+
return RCL_RET_OK;
252+
}
253+
216254
rcl_ret_t
217255
rcl_system_clock_init(
218256
rcl_clock_t * clock,

rcl/src/rcl/wait.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -544,18 +544,27 @@ rcl_wait(rcl_wait_set_t * wait_set, int64_t timeout)
544544
}
545545
}
546546

547-
int64_t min_next_call_time[RCL_STEADY_TIME + 1];
548-
rcl_clock_t * clocks[RCL_STEADY_TIME + 1] = {NULL, NULL, NULL, NULL};
547+
int64_t min_next_call_time[RCL_RAW_STEADY_TIME + 1];
548+
rcl_clock_t * clocks[RCL_RAW_STEADY_TIME + 1] = {NULL, NULL, NULL, NULL};
549549

550550
// asserts to make sure nobody changes the ordering of RCL_ROS_TIME,
551-
// RCL_SYSTEM_TIME and RCL_STEADY_TIME
552-
static_assert(RCL_ROS_TIME < RCL_STEADY_TIME + 1, "RCL_ROS_TIME won't fit in the array");
553-
static_assert(RCL_SYSTEM_TIME < RCL_STEADY_TIME + 1, "RCL_SYSTEM_TIME won't fit in the array");
554-
static_assert(RCL_STEADY_TIME < RCL_STEADY_TIME + 1, "RCL_STEADY_TIME won't fit in the array");
551+
// RCL_SYSTEM_TIME, RCL_STEADY_TIME and RCL_RAW_STEADY_TIME
552+
static_assert(RCL_ROS_TIME < RCL_RAW_STEADY_TIME + 1, "RCL_ROS_TIME won't fit in the array");
553+
static_assert(
554+
RCL_SYSTEM_TIME < RCL_RAW_STEADY_TIME + 1,
555+
"RCL_SYSTEM_TIME won't fit in the array");
556+
static_assert(
557+
RCL_STEADY_TIME < RCL_RAW_STEADY_TIME + 1,
558+
"RCL_STEADY_TIME won't fit in the array");
559+
static_assert(
560+
RCL_RAW_STEADY_TIME < RCL_RAW_STEADY_TIME + 1,
561+
"RCL_RAW_STEADY_TIME won't fit in the array");
555562

556563
min_next_call_time[RCL_ROS_TIME] = INT64_MAX;
557564
min_next_call_time[RCL_SYSTEM_TIME] = INT64_MAX;
558565
min_next_call_time[RCL_STEADY_TIME] = INT64_MAX;
566+
min_next_call_time[RCL_RAW_STEADY_TIME] = INT64_MAX;
567+
559568

560569
if (!is_non_blocking) {
561570
for (size_t t_idx = 0; t_idx < wait_set->impl->timer_index; ++t_idx) {
@@ -623,7 +632,7 @@ rcl_wait(rcl_wait_set_t * wait_set, int64_t timeout)
623632
int64_t min_timeout = has_valid_timeout ? timeout : INT64_MAX;
624633

625634
// determine the min timeout of all clocks
626-
for (size_t i = RCL_ROS_TIME; i <= RCL_STEADY_TIME; i++) {
635+
for (size_t i = RCL_ROS_TIME; i <= RCL_RAW_STEADY_TIME; i++) {
627636
if (clocks[i] == NULL) {
628637
continue;
629638
}

rcl/test/rcl/test_time.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,22 @@ TEST(rcl_time, default_clock_instanciation) {
239239
});
240240
ASSERT_TRUE(rcl_clock_valid(steady_clock));
241241

242+
auto * raw_steady_clock = static_cast<rcl_clock_t *>(
243+
allocator.zero_allocate(1, sizeof(rcl_clock_t), allocator.state));
244+
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
245+
{
246+
allocator.deallocate(raw_steady_clock, allocator.state);
247+
});
248+
retval = rcl_raw_steady_clock_init(raw_steady_clock, &allocator);
249+
EXPECT_EQ(retval, RCL_RET_OK) << rcl_get_error_string().str;
250+
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
251+
{
252+
EXPECT_EQ(
253+
RCL_RET_OK, rcl_raw_steady_clock_fini(
254+
raw_steady_clock)) << rcl_get_error_string().str;
255+
});
256+
ASSERT_TRUE(rcl_clock_valid(raw_steady_clock));
257+
242258
auto * system_clock = static_cast<rcl_clock_t *>(
243259
allocator.zero_allocate(1, sizeof(rcl_clock_t), allocator.state));
244260
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
@@ -272,6 +288,9 @@ TEST(rcl_time, specific_clock_instantiation) {
272288
EXPECT_EQ(
273289
rcl_steady_clock_fini(&uninitialized_clock), RCL_RET_ERROR) << rcl_get_error_string().str;
274290
rcl_reset_error();
291+
EXPECT_EQ(
292+
rcl_raw_steady_clock_fini(&uninitialized_clock), RCL_RET_ERROR) << rcl_get_error_string().str;
293+
rcl_reset_error();
275294
EXPECT_EQ(
276295
rcl_system_clock_fini(&uninitialized_clock), RCL_RET_ERROR) << rcl_get_error_string().str;
277296
rcl_reset_error();
@@ -303,6 +322,15 @@ TEST(rcl_time, specific_clock_instantiation) {
303322
ret = rcl_clock_fini(&steady_clock);
304323
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
305324
}
325+
{
326+
rcl_clock_t raw_steady_clock;
327+
rcl_ret_t ret = rcl_clock_init(RCL_RAW_STEADY_TIME, &raw_steady_clock, &allocator);
328+
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
329+
EXPECT_EQ(raw_steady_clock.type, RCL_RAW_STEADY_TIME) <<
330+
"Expected time source of type RCL_RAW_STEADY_TIME";
331+
ret = rcl_clock_fini(&raw_steady_clock);
332+
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
333+
}
306334
{
307335
rcl_clock_t fail_clock;
308336
rcl_clock_type_t undefined_type = (rcl_clock_type_t) 130;
@@ -344,6 +372,14 @@ TEST(rcl_time, rcl_clock_time_started) {
344372
ret = rcl_clock_fini(&steady_clock);
345373
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
346374
}
375+
{
376+
rcl_clock_t raw_steady_clock;
377+
rcl_ret_t ret = rcl_clock_init(RCL_RAW_STEADY_TIME, &raw_steady_clock, &allocator);
378+
ASSERT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
379+
ASSERT_TRUE(rcl_clock_time_started(&raw_steady_clock));
380+
ret = rcl_clock_fini(&raw_steady_clock);
381+
EXPECT_EQ(ret, RCL_RET_OK) << rcl_get_error_string().str;
382+
}
347383
}
348384

349385
TEST(rcl_time, rcl_time_difference) {

0 commit comments

Comments
 (0)