// Copyright 2015 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCL__TIME_H_
#define RCL__TIME_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "rcl/allocator.h"
#include "rcl/macros.h"
#include "rcl/types.h"
#include "rcl/visibility_control.h"
#include "rcutils/time.h"
/// Convenience macro to convert seconds to nanoseconds.
#define RCL_S_TO_NS RCUTILS_S_TO_NS
/// Convenience macro to convert milliseconds to nanoseconds.
#define RCL_MS_TO_NS RCUTILS_MS_TO_NS
/// Convenience macro to convert microseconds to nanoseconds.
#define RCL_US_TO_NS RCUTILS_US_TO_NS
/// Convenience macro to convert nanoseconds to seconds.
#define RCL_NS_TO_S RCUTILS_NS_TO_S
/// Convenience macro to convert nanoseconds to milliseconds.
#define RCL_NS_TO_MS RCUTILS_NS_TO_MS
/// Convenience macro to convert nanoseconds to microseconds.
#define RCL_NS_TO_US RCUTILS_NS_TO_US
/// A single point in time, measured in nanoseconds since the Unix epoch.
typedef rcutils_time_point_value_t rcl_time_point_value_t;
/// A duration of time, measured in nanoseconds.
typedef rcutils_duration_value_t rcl_duration_value_t;
/// Time source type, used to indicate the source of a time measurement.
/**
* RCL_ROS_TIME will report the latest value reported by a ROS time source, or
* if a ROS time source is not active it reports the same as RCL_SYSTEM_TIME.
* For more information about ROS time sources, refer to the design document:
* http://design.ros2.org/articles/clock_and_time.html
*
* RCL_SYSTEM_TIME reports the same value as the system clock.
*
* RCL_STEADY_TIME reports a value from a monotonically increasing clock.
*/
typedef enum rcl_clock_type_t
{
RCL_CLOCK_UNINITIALIZED = 0,
RCL_ROS_TIME,
RCL_SYSTEM_TIME,
RCL_STEADY_TIME
} rcl_clock_type_t;
/// A duration of time, measured in nanoseconds and its source.
typedef struct rcl_duration_t
{
/// Duration in nanoseconds and its source.
rcl_duration_value_t nanoseconds;
} rcl_duration_t;
/// Enumeration to describe the type of time jump.
typedef enum rcl_clock_change_t
{
/// The source before and after the jump is ROS_TIME.
RCL_ROS_TIME_NO_CHANGE = 1,
/// The source switched to ROS_TIME from SYSTEM_TIME.
RCL_ROS_TIME_ACTIVATED = 2,
/// The source switched to SYSTEM_TIME from ROS_TIME.
RCL_ROS_TIME_DEACTIVATED = 3,
/// The source before and after the jump is SYSTEM_TIME.
RCL_SYSTEM_TIME_NO_CHANGE = 4
} rcl_clock_change_t;
/// Struct to describe a jump in time.
typedef struct rcl_time_jump_t
{
/// Indicate whether or not the source of time changed.
rcl_clock_change_t clock_change;
/// The new time minus the last time before the jump.
rcl_duration_t delta;
} rcl_time_jump_t;
/// Signature of a time jump callback.
/// \param[in] time_jump A description of the jump in time.
/// \param[in] before_jump Every jump callback is called twice: once before the clock changes and
/// once after. This is true the first call and false the second.
/// \param[in] user_data A pointer given at callback registration which is passed to the callback.
typedef void (* rcl_jump_callback_t)(
const struct rcl_time_jump_t * time_jump,
bool before_jump,
void * user_data);
/// Describe the prerequisites for calling a time jump callback.
typedef struct rcl_jump_threshold_t
{
/// True to call callback when the clock type changes.
bool on_clock_change;
/// A positive duration indicating the minimum jump forwards to be considered exceeded, or zero
/// to disable.
rcl_duration_t min_forward;
/// A negative duration indicating the minimum jump backwards to be considered exceeded, or zero
/// to disable.
rcl_duration_t min_backward;
} rcl_jump_threshold_t;
/// Struct to describe an added callback.
typedef struct rcl_jump_callback_info_t
{
/// Callback to fucntion.
rcl_jump_callback_t callback;
/// Threshold to decide when to call the callback.
rcl_jump_threshold_t threshold;
/// Pointer passed to the callback.
void * user_data;
} rcl_jump_callback_info_t;
/// Encapsulation of a time source.
typedef struct rcl_clock_t
{
/// Clock type
enum rcl_clock_type_t type;
/// An array of added jump callbacks.
rcl_jump_callback_info_t * jump_callbacks;
/// Number of callbacks in jump_callbacks.
size_t num_jump_callbacks;
/// Pointer to get_now function
rcl_ret_t (* get_now)(void * data, rcl_time_point_value_t * now);
// void (*set_now) (rcl_time_point_value_t);
/// Clock storage
void * data;
/// Custom allocator used for internal allocations.
rcl_allocator_t allocator;
} rcl_clock_t;
/// A single point in time, measured in nanoseconds, the reference point is based on the source.
typedef struct rcl_time_point_t
{
/// Nanoseconds of the point in time
rcl_time_point_value_t nanoseconds;
/// Clock type of the point in time
rcl_clock_type_t clock_type;
} rcl_time_point_t;
// typedef struct rcl_rate_t
// {
// rcl_time_point_value_t trigger_time;
// int64_t period;
// rcl_clock_type_t clock;;
// } rcl_rate_t;
// TODO(tfoote) integrate rate and timer implementations
/// Check if the clock has valid values.
/**
* This function returns true if the time source appears to be valid.
* It will check that the type is not uninitialized, and that pointers
* are not invalid.
* Note that if data is uninitialized it may give a false positive.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | Yes
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] clock the handle to the clock which is being queried
* \return true if the source is believed to be valid, otherwise return false.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
bool
rcl_clock_valid(rcl_clock_t * clock);
/// Initialize a clock based on the passed type.
/**
* This will allocate all necessary internal structures, and initialize variables.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes [1]
* Thread-Safe | No [2]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] If `clock_type` is `RCL_ROS_TIME`
* [2] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object.
*
* \param[in] clock_type the type identifying the time source to provide
* \param[in] clock the handle to the clock which is being initialized
* \param[in] allocator The allocator to use for allocations
* \return `RCL_RET_OK` if the time source was successfully initialized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_clock_init(
enum rcl_clock_type_t clock_type, rcl_clock_t * clock,
rcl_allocator_t * allocator);
/// Finalize a clock.
/**
* This will deallocate all necessary internal structures, and clean up any variables.
* It can be combined with any of the init functions.
*
* Passing a clock with type RCL_CLOCK_UNINITIALIZED will result in
* RCL_RET_INVALID_ARGUMENT being returned.
*
* This function is not thread-safe with any other function operating on the same
* clock object.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object associated with the
* `clock` object.
*
* \param[in] clock the handle to the clock which is being finalized
* \return `RCL_RET_OK` if the time source was successfully finalized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_clock_fini(
rcl_clock_t * clock);
/// Initialize a clock as a RCL_ROS_TIME time source.
/**
* This will allocate all necessary internal structures, and initialize variables.
* It is specifically setting up a RCL_ROS_TIME time source.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [2] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object.
*
* \param[in] clock the handle to the clock which is being initialized
* \param[in] allocator The allocator to use for allocations
* \return `RCL_RET_OK` if the time source was successfully initialized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_BAD_ALLOC` if allocating memory failed, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_ros_clock_init(
rcl_clock_t * clock,
rcl_allocator_t * allocator);
/// Finalize a clock as a `RCL_ROS_TIME` time source.
/**
* This will deallocate all necessary internal structures, and clean up any variables.
* It is specifically setting up a `RCL_ROS_TIME` time source. It is expected
* to be paired with the init fuction.
*
* This function is not thread-safe with any other function operating on the same
* clock object.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object associated with the
* `clock` object.
*
* \param[in] clock the handle to the clock which is being initialized
* \return `RCL_RET_OK` if the time source was successfully finalized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_ros_clock_fini(
rcl_clock_t * clock);
/// Initialize a clock as a `RCL_STEADY_TIME` time source.
/**
* This will allocate all necessary internal structures, and initialize variables.
* It is specifically setting up a `RCL_STEADY_TIME` time source.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object.
*
* \param[in] clock the handle to the clock which is being initialized
* \param[in] allocator The allocator to use for allocations
* \return `RCL_RET_OK` if the time source was successfully initialized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_steady_clock_init(
rcl_clock_t * clock,
rcl_allocator_t * allocator);
/// Finalize a clock as a `RCL_STEADY_TIME` time source.
/**
* Finalize the clock as a `RCL_STEADY_TIME` time source.
*
* This will deallocate all necessary internal structures, and clean up any variables.
* It is specifically setting up a steady time source. It is expected to be
* paired with the init fuction.
*
* This function is not thread-safe with any other function operating on the same
* clock object.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object associated with the
* `clock` object.
*
* \param[in] clock the handle to the clock which is being initialized
* \return `RCL_RET_OK` if the time source was successfully finalized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_steady_clock_fini(
rcl_clock_t * clock);
/// Initialize a clock as a `RCL_SYSTEM_TIME` time source.
/**
* Initialize the clock as a `RCL_SYSTEM_TIME` time source.
*
* This will allocate all necessary internal structures, and initialize variables.
* It is specifically setting up a system time source.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object associated with the
* `clock` object.
*
* \param[in] clock the handle to the clock which is being initialized
* \param[in] allocator The allocator to use for allocations
* \return `RCL_RET_OK` if the time source was successfully initialized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_system_clock_init(
rcl_clock_t * clock,
rcl_allocator_t * allocator);
/// Finalize a clock as a `RCL_SYSTEM_TIME` time source.
/**
* Finalize the clock as a `RCL_SYSTEM_TIME` time source.
*
* This will deallocate all necessary internal structures, and clean up any variables.
* It is specifically setting up a system time source. It is expected to be paired with
* the init fuction.
*
* This function is not thread-safe with any function operating on the same clock object.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object associated with the
* `clock` object.
*
* \param[in] clock the handle to the clock which is being initialized.
* \return `RCL_RET_OK` if the time source was successfully finalized, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_system_clock_fini(
rcl_clock_t * clock);
/// Compute the difference between two time points
/**
* This function takes two time points and computes the duration between them.
* The two time points must be using the same time abstraction, and the
* resultant duration will also be of the same abstraction.
*
* The value will be computed as duration = finish - start. If start is after
* finish the duration will be negative.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | Yes
* Uses Atomics | No
* Lock-Free | Yes
*
* \param[in] start The time point for the start of the duration.
* \param[in] finish The time point for the end of the duration.
* \param[out] delta The duration between the start and finish.
* \return `RCL_RET_OK` if the difference was computed successfully, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_difference_times(
rcl_time_point_t * start, rcl_time_point_t * finish, rcl_duration_t * delta);
/// Fill the time point value with the current value of the associated clock.
/**
* This function will populate the data of the time_point_value object with the
* current value from it's associated time abstraction.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | Yes
* Uses Atomics | Yes [1]
* Lock-Free | Yes
*
* [1] If `clock` is of `RCL_ROS_TIME` type.
*
* \param[in] clock The time source from which to set the value.
* \param[out] time_point_value The time_point value to populate.
* \return `RCL_RET_OK` if the last call time was retrieved successfully, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_clock_get_now(rcl_clock_t * clock, rcl_time_point_value_t * time_point_value);
/// Enable the ROS time abstraction override.
/**
* This method will enable the ROS time abstraction override values,
* such that the time source will report the set value instead of falling
* back to system time.
*
* This function is not thread-safe with `rcl_clock_add_jump_callback`,
* nor `rcl_clock_remove_jump_callback` functions when used on the same
* clock object.
*
*
* Attribute | Adherence [1]
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [2]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Only applies to the function itself, as jump callbacks may not abide to it.
* [2] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
*
* \param[in] clock The clock to enable.
* \return `RCL_RET_OK` if the time source was enabled successfully, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_enable_ros_time_override(rcl_clock_t * clock);
/// Disable the ROS time abstraction override.
/**
* This method will disable the `RCL_ROS_TIME` time abstraction override values,
* such that the time source will report the system time even if a custom
* value has been set.
*
* This function is not thread-safe with `rcl_clock_add_jump_callback`,
* nor `rcl_clock_remove_jump_callback` functions when used on the same
* clock object.
*
*
* Attribute | Adherence [1]
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [2]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Only applies to the function itself, as jump callbacks may not abide to it.
* [2] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
*
* \param[in] clock The clock to disable.
* \return `RCL_RET_OK` if the time source was disabled successfully, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_disable_ros_time_override(rcl_clock_t * clock);
/// Check if the `RCL_ROS_TIME` time source has the override enabled.
/**
* This will populate the is_enabled object to indicate if the
* time overide is enabled. If it is enabled, the set value will be returned.
* Otherwise this time source will return the equivalent to system time abstraction.
*
* This function is not thread-safe with `rcl_enable_ros_time_override` nor
* `rcl_disable_ros_time_override` functions when used on the same clock object.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
*
* \param[in] clock The clock to query.
* \param[out] is_enabled Whether the override is enabled..
* \return `RCL_RET_OK` if the time source was queried successfully, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_is_enabled_ros_time_override(
rcl_clock_t * clock, bool * is_enabled);
/// Set the current time for this `RCL_ROS_TIME` time source.
/**
* This function will update the internal storage for the `RCL_ROS_TIME`
* time source.
* If queried and override enabled the time source will return this value,
* otherwise it will return the system time.
*
* This function is not thread-safe with `rcl_clock_add_jump_callback`,
* nor `rcl_clock_remove_jump_callback` functions when used on the same
* clock object.
*
*
* Attribute | Adherence [1]
* ------------------ | -------------
* Allocates Memory | No
* Thread-Safe | No [2]
* Uses Atomics | Yes
* Lock-Free | Yes
*
* [1] Only applies to the function itself, as jump callbacks may not abide to it.
* [2] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
*
* \param[in] clock The clock to update.
* \param[in] time_value The new current time.
* \return `RCL_RET_OK` if the time source was set successfully, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occur.
*/
RCL_PUBLIC
RCL_WARN_UNUSED
rcl_ret_t
rcl_set_ros_time_override(
rcl_clock_t * clock, rcl_time_point_value_t time_value);
/// Add a callback to be called when a time jump exceeds a threshold.
/**
* The callback is called twice when the threshold is exceeded: once before the clock is
* updated, and once after.
* The user_data pointer is passed to the callback as the last argument.
* A callback and user_data pair must be unique among the callbacks added to a clock.
*
* This function is not thread-safe with `rcl_clock_remove_jump_callback`,
* `rcl_enable_ros_time_override`, `rcl_disable_ros_time_override` nor
* `rcl_set_ros_time_override` functions when used on the same clock object.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object associated with the
* `clock` object.
*
* \param[in] clock A clock to add a jump callback to.
* \param[in] threshold Criteria indicating when to call the callback.
* \param[in] callback A callback to call.
* \param[in] user_data A pointer to be passed to the callback.
* \return `RCL_RET_OK` if the callback was added successfully, or
* \return `RCL_RET_BAD_ALLOC` if a memory allocation failed, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` an unspecified error occurs.
*/
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);
/// Remove a previously added time jump callback.
/**
* This function is not thread-safe with `rcl_clock_add_jump_callback`
* `rcl_enable_ros_time_override`, `rcl_disable_ros_time_override` nor
* `rcl_set_ros_time_override` functions when used on the same clock object.
*
*
* Attribute | Adherence
* ------------------ | -------------
* Allocates Memory | Yes
* Thread-Safe | No [1]
* Uses Atomics | No
* Lock-Free | Yes
*
* [1] Function is reentrant, but concurrent calls on the same `clock` object are not safe.
* Thread-safety is also affected by that of the `allocator` object associated with the
* `clock` object.
*
* \param[in] clock The clock to remove a jump callback from.
* \param[in] callback The callback to call.
* \param[in] user_data A pointer to be passed to the callback.
* \return `RCL_RET_OK` if the callback was added successfully, or
* \return `RCL_RET_BAD_ALLOC` if a memory allocation failed, or
* \return `RCL_RET_INVALID_ARGUMENT` if any arguments are invalid, or
* \return `RCL_RET_ERROR` the callback was not found or an unspecified error occurs.
*/
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);
#ifdef __cplusplus
}
#endif
#endif // RCL__TIME_H_