/********************************************************************* * Software License Agreement (BSD License) * * Copyright (c) 2024 * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. *********************************************************************/ #ifndef ROBOT_TIMER_H #define ROBOT_TIMER_H #include #include #include "robot_time_decl.h" #include #include #include #include #include #include namespace robot { /** * @brief Structure containing information about a timer event * * Similar to ros::TimerEvent, this structure is passed to timer callbacks * and contains timing information about the current and previous timer events. */ struct ROBOT_TIME_DECL TimerEvent { /** * @brief The time when the current callback was actually called */ Time current_real; /** * @brief The time when the current callback was expected to be called */ Time current_expected; /** * @brief The time when the previous callback was actually called */ Time last_real; /** * @brief The time when the previous callback was expected to be called */ Time last_expected; /** * @brief The time between the last two callbacks */ Duration last_duration; /** * @brief Default constructor */ TimerEvent() : current_real(Time::now()) , current_expected(Time::now()) , last_real(Time::ZERO) , last_expected(Time::ZERO) , last_duration(Duration::ZERO) {} }; /** * @class Timer * @brief A class to call a callback function at a specified rate * * This class is similar to ros::Timer. It creates a separate thread that * calls a callback function at a specified period. The callback receives * a TimerEvent structure containing timing information. * * Example usage: * @code * void myCallback(const robot::TimerEvent& event) { * // Do something periodically * } * * robot::Timer timer(robot::Duration(1.0), myCallback); * timer.start(); * // ... later ... * timer.stop(); * @endcode */ class ROBOT_TIME_DECL Timer { public: /** * @brief Callback function type for timer events */ using Callback = std::function; /** * @brief Default constructor - creates an uninitialized timer * Timer must be assigned or constructed with parameters before use */ Timer(); /** * @brief Constructor * @param period The period between timer callbacks * @param callback The callback function to call * @param oneshot If true, the timer will only fire once. If false, it will fire repeatedly. * @param autostart If true, the timer will start automatically. If false, you must call start(). */ Timer(const Duration& period, const Callback& callback, bool oneshot = false, bool autostart = true); /** * @brief Constructor with member function pointer * @param period The period between timer callbacks * @param callback Member function pointer to call * @param obj Object instance to call the member function on * @param oneshot If true, the timer will only fire once. If false, it will fire repeatedly. * @param autostart If true, the timer will start automatically. If false, you must call start(). * * Example: * @code * class MyClass { * void callback(const robot::TimerEvent& event) { } * }; * MyClass obj; * robot::Timer timer(robot::Duration(1.0), &MyClass::callback, &obj); * @endcode */ template Timer(const Duration& period, void (T::*callback)(const TimerEvent&), T* obj, bool oneshot = false, bool autostart = true) : Timer(period, [obj, callback](const TimerEvent& event) { (obj->*callback)(event); }, oneshot, autostart) {} /** * @brief Destructor - stops the timer and joins the thread */ ~Timer(); /** * @brief Start the timer */ void start(); /** * @brief Stop the timer */ void stop(); /** * @brief Check if the timer has been started * @return True if the timer is running, false otherwise */ bool hasStarted() const; /** * @brief Check if the timer is one-shot * @return True if the timer is one-shot, false if it repeats */ bool isOneShot() const; /** * @brief Set whether the timer is one-shot * @param oneshot If true, the timer will only fire once */ void setOneShot(bool oneshot); /** * @brief Get the timer period * @return The period between timer callbacks */ Duration getPeriod() const; /** * @brief Set the timer period * @param period The new period between timer callbacks */ void setPeriod(const Duration& period); // Non-copyable Timer(const Timer&) = delete; Timer& operator=(const Timer&) = delete; // Movable Timer(Timer&& other) noexcept; Timer& operator=(Timer&& other) noexcept; private: /** * @brief The timer thread function */ void timerThread(); Duration period_; ///< Period between callbacks Callback callback_; ///< Callback function bool oneshot_; ///< Whether timer is one-shot std::atomic running_; ///< Whether timer is running std::atomic should_stop_; ///< Flag to stop the timer thread std::thread thread_; ///< Timer thread mutable std::mutex mutex_; ///< Mutex for thread safety std::condition_variable cv_; ///< Condition variable for timing Time last_real_; ///< Last actual callback time Time last_expected_; ///< Last expected callback time }; } // namespace robot #endif // ROBOT_TIMER_H