API for timers in timers.h

This commit is contained in:
William Woodall 2015-12-04 09:37:43 -08:00
parent 3e5298bac0
commit 821bbf7ce6
2 changed files with 315 additions and 4 deletions

308
rcl/include/rcl/timer.h Normal file
View file

@ -0,0 +1,308 @@
// 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__TIMER_H_
#define RCL__TIMER_H_
#if __cplusplus
extern "C"
{
#endif
#include <stdbool.h>
#include "rcl/allocator.h"
#include "rcl/time.h"
#include "rcl/types.h"
#include "rmw/rmw.h"
struct rcl_timer_impl_t;
/// Handle for a ROS timer.
typedef struct rcl_timer_t {
/// Private implementation pointer.
rcl_timer_impl_t * impl;
} rcl_timer_t;
/// User callback signature for timers.
/* The first argument the callback gets is a pointer to the timer.
* This can be used to cancel the timer, query about the time until the next
* timer callback, exchange the callback with a different one, etc.
*
* The only caveat is that the function rcl_timer_get_last_call_time will
* return the time just before the callback was called.
* Therefore the second argument given is the time when the previous callback
* was called, since that information is no longer accessible via the timer.
*/
typedef void (* rcl_timer_callback_t)(rcl_timer_t *, rcl_time_t);
/// Return a zero initialized timer.
rcl_timer_t
rcl_get_zero_initialized_timer();
/// Initialize a timer.
/* A timer consists of a callback function and a period.
* A timer can be added to a wait set and waited on, such that the wait set
* will wake up when a timer is ready to be executed.
*
* A timer simply holds state and does not actively call periodically.
* It does not create any threads or register interrupts or signals.
* For blocking behavior it can be used in conjunction with a wait set and
* rcl_wait().
* When rcl_timer_is_ready() returns true, the timer must still be called
* explicitly using rcl_timer_call().
*
* The timer handle must be a pointer to an allocated and zero initialized
* timer struct.
* Calling this function on an already initialized timer will fail.
* Calling this function on a timer struct which has been allocated but not
* zero initialized is undefined behavior.
*
* The period is a timer duration (rather an absolute time in the future).
* If the period is 0 seconds and 0 nanoseconds then it will always be ready.
*
* The callback must be a function which returns void and takes two arguments,
* the first being a pointer to the associated timer, and the second a time
* struct which is the time of the previous call or when the timer was created
* if it is the first call to the callback.
*
* This function is not thread-safe.
*
* \param[inout] timer the timer handle to be initialized
* \param[in] period the duration between calls to the callback in nanoseconds
* \param[in] callback the user defined function to be called every period
* \param[in] allocator the allocator to use for allocations
* \return RCL_RET_OK if the timer was initialized successfully, or
* RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* RCL_RET_BAD_ALLOC if allocating memory failed, or
* RCL_RET_ERROR an unspecified error occur.
*/
rcl_ret_t
rcl_timer_init(
rcl_timer_t * timer,
uint64_t period,
const rcl_timer_callback_t callback,
rcl_allocator_t allocator);
/// Finalize a timer.
/* This function will deallocate any memory and make the timer invalid.
*
* A timer that is already invalid (zero initialized) or NULL will not fail.
*
* This function is not thread-safe with any rcl_timer_* functions used on the
* same timer object.
*
* \param[inout] timer the handle to the timer to be finalized.
* \return RCL_RET_OK if the timer was finalized successfully, or
* RCL_RET_ERROR an unspecified error occur.
*/
rcl_ret_t
rcl_timer_fini(rcl_timer_t * timer);
/// Call the timer's callback and set the last call time to the current time.
/* This function will call the callback and change the last call time even if
* the timer's period has not yet elapsed.
* It is up to the calling code to make sure the period has elapsed by first
* calling rcl_timer_is_ready().
* The order of operations in this command are as follows:
*
* - Ensure the timer has not been canceled.
* - Get the current time into a temporary rcl_time_t.
* - Exchange the current time with the last call time of the timer.
* - Call the callback, with this timer and the exchanged last call time.
*
* During the callback the timer can be canceled or have its period and/or
* callback modified.
*
* This function is thread-safe, but the user's callback may not be.
* This function is lock-free so long as the C11's stdatomic.h function
* atomic_is_lock_free() returns true for atomic_int_least64_t, but the user's
* callback may not be lock-free.
*
* \param[inout] timer the handle to the timer to call
* \return RCL_RET_OK if the timer was called successfully, or
* RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* RCL_RET_TIMER_INVALID if the timer is invalid, or
* RCL_RET_TIMER_CANCELED if the timer has been canceled, or
* RCL_RET_ERROR an unspecified error occur.
*/
rcl_ret_t
rcl_timer_call(rcl_timer_t * timer);
/// Calculates whether or not the timer should be called.
/* The result is true if the time until next call is less than, or equal to, 0
* and the timer has not been canceled.
* Otherwise the result is false, indicating the period has not elapsed.
*
* The is_ready argument must point to an allocated bool object, as the result
* is copied into it.
*
* This function is thread-safe.
* This function is lock-free so long as the C11's stdatomic.h function
* atomic_is_lock_free() returns true for atomic_int_least64_t.
*
* \param[in] timer the handle to the timer which is being checked
* \param[out] is_ready the bool used to store the result of the calculation
* \return RCL_RET_OK if the last call time was retrieved successfully, or
* RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* RCL_RET_TIMER_INVALID if the timer is invalid, or
* RCL_RET_ERROR an unspecified error occur.
*/
rcl_ret_t
rcl_timer_is_ready(const rcl_timer_t * timer, bool * is_ready);
/// Calculate and retrieve the time until the next call in nanoseconds.
/* This function calculates the time until the next call by adding the timer's
* period to the last call time and subtracting that sum from the current time.
* The calculated time until the next call can be positive, indicating that it
* is not ready to be called as the period has not elapsed since the last call.
* The calculated time until the next call can also be 0 or negative,
* indicating that the period has elapsed since the last call and the timer
* should be called.
* A negative value indicates the timer call is overdue by that amount.
*
* The time_until_next_call argument must point to an allocated int64_t, as the
* the time until is coped into that instance.
*
* This function is thread-safe.
* This function is lock-free so long as the C11's stdatomic.h function
* atomic_is_lock_free() returns true for atomic_int_least64_t.
*
* \param[in] timer the handle to the timer that is being queried
* \param[out] time_until_next_call the output variable for the result
* \return RCL_RET_OK if the timer until next call was successfully calculated, or
* RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* RCL_RET_TIMER_INVALID if the timer is invalid, or
* RCL_RET_ERROR an unspecified error occur.
*/
rcl_ret_t
rcl_timer_get_time_until_next_call(const rcl_timer_t * timer, int64_t * time_until_next_call);
/// Retrieve the time of when the previous call to rcl_timer_call() occurred.
/* This function retrieves the internal time and copies it into the given
* rcl_time_t struct.
*
* Calling this function within a callback will not return the previous time
* but instead the time of when the current callback was called.
*
* The last_call_time argument must be a pointer to an already allocated
* rcl_time_t struct.
*
* This function is thread-safe.
* This function is lock-free so long as the C11's stdatomic.h function
* atomic_is_lock_free() returns true for atomic_int_least64_t.
*
* \param[in] timer the handle to the timer which is being queried
* \param[out] last_call_time the rcl_time_t struct in which the time is stored
* \return RCL_RET_OK if the last call time was retrieved successfully, or
* RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* RCL_RET_TIMER_INVALID if the timer is invalid, or
* RCL_RET_ERROR an unspecified error occur.
*/
rcl_ret_t
rcl_timer_get_last_call_time(const rcl_timer_t * timer, rcl_time_t * last_call_time);
/// Return the current timer callback.
/* This function can fail, and therefore return NULL, if:
* - timer is NULL
* - timer has not been initialized (the implementation is invalid)
*
* This function is thread-safe.
* This function is lock-free so long as the C11's stdatomic.h function
* atomic_is_lock_free() returns true for atomic_uintptr_t.
*
* \param[in] timer handle to the timer from the callback should be returned
* \return function pointer to the callback, or NULL if an error occurred
*/
rcl_timer_callback_t
rcl_timer_get_callback(const rcl_timer_t * timer);
/// Exchange the current timer callback and return the current callback.
/* This function can fail, and therefore return NULL, if:
* - timer is NULL
* - timer has not been initialized (the implementation is invalid)
* - the new_callback argument is NULL
*
* This function is thread-safe.
* This function is lock-free so long as the C11's stdatomic.h function
* atomic_is_lock_free() returns true for atomic_uintptr_t.
*
* \param[inout] timer handle to the timer from the callback should be returned
* \param[in] timer handle to the timer from the callback should be returned
* \return function pointer to the old callback, or NULL if an error occurred
*/
rcl_timer_callback_t
rcl_timer_exchange_callback(rcl_time_t * timer, const rcl_timer_callback_t new_callback);
/// Cancel a timer.
/* When a timer is canceled, rcl_timer_is_ready() will return false for that
* timer, and rcl_timer_call() will fail with RCL_RET_TIMER_CANCELED.
*
* A canceled timer can be reset with rcl_timer_reset(), and then used again.
* Calling this function on an already canceled timer will succeed.
*
* This function is thread-safe.
* This function is lock-free.
*
* \param[inout] timer the timer to be canceled
* \return RCL_RET_OK if the last call time was retrieved successfully, or
* RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* RCL_RET_TIMER_INVALID if the timer is invalid, or
* RCL_RET_ERROR an unspecified error occur.
*/
rcl_ret_t
rcl_timer_cancel(rcl_timer_t * timer);
/// Retrieve the canceled state of a timer.
/* If the timer is canceled true will be stored in the is_canceled argument.
* Otherwise false will be stored in the is_canceled argument.
*
* The is_canceled argument must point to an allocated bool, as the result is
* copied into this variable.
*
* This function is thread-safe.
* This function is lock-free.
*
* \param[in] timer the timer to be queried
* \return RCL_RET_OK if the last call time was retrieved successfully, or
* RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* RCL_RET_TIMER_INVALID if the timer is invalid, or
* RCL_RET_ERROR an unspecified error occur.
*/
rcl_ret_t
rcl_timer_is_canceled(const rcl_timer_t * timer, bool * is_canceled);
/// Reset a timer.
/* This function can be called on a timer, canceled or not.
* For all timers it will reset the last call time to now.
* For canceled timers it will additionally make the timer not canceled.
*
* This function is thread-safe.
* This function is lock-free so long as the C11's stdatomic.h function
* atomic_is_lock_free() returns true for atomic_int_least64_t.
*
* \param[inout] timer the timer to be reset
* \return RCL_RET_OK if the last call time was retrieved successfully, or
* RCL_RET_INVALID_ARGUMENT if any arguments are invalid, or
* RCL_RET_TIMER_INVALID if the timer is invalid, or
* RCL_RET_ERROR an unspecified error occur.
*/
rcl_ret_t
rcl_timer_reset(rcl_timer_t * timer);
#if __cplusplus
}
#endif
#endif // RCL__TIMER_H_

View file

@ -35,9 +35,12 @@ typedef rmw_ret_t rcl_ret_t;
// rcl service client specific ret codes in 5XX // rcl service client specific ret codes in 5XX
// rcl service server specific ret codes in 6XX // rcl service server specific ret codes in 6XX
// rcl guard condition specific ret codes in 7XX // rcl guard condition specific ret codes in 7XX
// rcl wait and wait set specific ret codes in 8XX // rcl timer specific ret codes in 8XX
#define RCL_RET_WAIT_SET_INVALID 800 #define RCL_RET_TIMER_INVALID 800
#define RCL_RET_WAIT_SET_EMPTY 801 #define RCL_RET_TIMER_CANCELED 801
#define RCL_RET_WAIT_SET_FULL 802 // rcl wait and wait set specific ret codes in 9XX
#define RCL_RET_WAIT_SET_INVALID 900
#define RCL_RET_WAIT_SET_EMPTY 901
#define RCL_RET_WAIT_SET_FULL 902
#endif // RCL__TYPES_H_ #endif // RCL__TYPES_H_