Timer APIs

Timer

The Timer component provides a cross-platform API for executing callback functions with a specified period. The timer can be started, stopped, and restarted, and the timer can have an optional initial delay before the first callback is executed. The timer can be configured to run once or repeatedly.

The timer API is implemented using the Task component, and the timer callback is executed in the context of the timer task.

Code examples for the task API are provided in the timer example folder.

API Reference

Header File

Classes

class Timer : public espp::BaseComponent

A timer that can be used to schedule tasks to run at a later time.

A timer can be used to schedule a task to run at a later time. The timer will run in the background and will call the task when the time is up. The timer can be canceled at any time. A timer can be configured to run once or to repeat.

The timer uses a task to run in the background. The task will sleep until the timer is ready to run. When the timer is ready to run, the task will call the callback function. The callback function can return true to cancel the timer or false to keep the timer running. If the timer is configured to repeat, then the callback function will be called again after the period has elapsed. If the timer is configured to run once, then the callback function will only be called once.

The timer can be configured to start automatically when it is constructed. If the timer is not configured to start automatically, then the timer can be started by calling start(). The timer can be canceled at any time by calling cancel().

Timer Example 1

    auto timer_fn = []() {
      static size_t iterations{0};
      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
      iterations++;
      // we don't want to stop, so return false
      return false;
    };
    auto timer = espp::Timer({.name = "Timer 1",
                              .period = 500ms,
                              .callback = timer_fn,
                              .log_level = espp::Logger::Verbosity::DEBUG});

Timer Watchdog Example

    static constexpr bool panic_on_watchdog_timeout = false;
    espp::Task::configure_task_watchdog(300ms, panic_on_watchdog_timeout);
    auto timer_fn = []() {
      static size_t iterations{0};
      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
      iterations++;
      // we don't want to stop, so return false
      return false;
    };
    auto timer = espp::Timer({.name = "Timer 1",
                              .period = 500ms,
                              .callback = timer_fn,
                              .log_level = espp::Logger::Verbosity::DEBUG});
    timer.start_watchdog(); // start the watchdog timer for this timer
    std::this_thread::sleep_for(500ms);
    std::error_code ec;
    std::string watchdog_info = espp::Task::get_watchdog_info(ec);
    if (ec) {
      fmt::print("Error getting watchdog info: {}\n", ec.message());
    } else if (!watchdog_info.empty()) {
      fmt::print("Watchdog info: {}\n", watchdog_info);
    } else {
      fmt::print("No watchdog info available\n");
    }
    // NOTE: the timer and the watchdog will both automatically get stopped when
    // the task goes out of scope and is destroyed.

Timer Delay Example

    auto timer_fn = []() {
      static size_t iterations{0};
      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
      iterations++;
      // we don't want to stop, so return false
      return false;
    };
    auto timer =
        espp::Timer({.name = "Timer 1",
                     .period = 500ms,
                     .delay = 500ms,
                     .callback = timer_fn,
                     .auto_start = false, // don't start the timer automatically, we'll call start()
                     .log_level = espp::Logger::Verbosity::DEBUG});
    timer.start();
    std::this_thread::sleep_for(2s);
    logger.info("Cancelling timer for 2 seconds");
    timer.cancel();
    std::this_thread::sleep_for(2s);
    timer.start();
    std::this_thread::sleep_for(2s);
    logger.info("Cancelling timer for 2 seconds");
    timer.cancel();
    std::this_thread::sleep_for(2s);
    timer.start(1s);

Oneshot Timer Example

    auto timer_fn = []() {
      static size_t iterations{0};
      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
      iterations++;
      // we don't want to stop, so return false
      return false;
    };
    auto timer = espp::Timer({.name = "Timer 1",
                              .period = 0ms, // one shot timer
                              .delay = 500ms,
                              .callback = timer_fn,
                              .log_level = espp::Logger::Verbosity::DEBUG});

Timer Cancel Itself Example

    auto timer_fn = []() {
      static size_t iterations{0};
      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
      iterations++;
      // cancel the timer after 3 iterations
      if (iterations == 3) {
        fmt::print("[{:.3f}] auto-cancelling timer\n", elapsed());
        return true;
      }
      return false;
    };
    auto timer = espp::Timer({.name = "Timer 1",
                              .period = 500ms,
                              .callback = timer_fn,
                              .stack_size_bytes = 6192,
                              .log_level = espp::Logger::Verbosity::DEBUG});

Oneshot Timer Cancel Itself Then Start again with Delay Example

    auto timer_fn = []() {
      static size_t iterations{0};
      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
      iterations++;
      // we want to stop, so return true
      return true;
    };
    auto timer = espp::Timer({.name = "Timer 1",
                              .period = 0ms, // one shot timer
                              .delay = 500ms,
                              .callback = timer_fn,
                              .stack_size_bytes = 4096,
                              .log_level = espp::Logger::Verbosity::DEBUG});
    std::this_thread::sleep_for(2s);
    timer.cancel();  // it will have already been cancelled by here, but this should be harmless
    timer.start(1s); // restart the timer with a 1 second delay

Timer Update Period Example

    auto timer_fn = []() {
      static size_t iterations{0};
      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
      iterations++;
      // we don't want to stop, so return false
      return false;
    };
    auto timer = espp::Timer({.name = "Timer 1",
                              .period = 500ms,
                              .callback = timer_fn,
                              .stack_size_bytes = 4096,
                              .log_level = espp::Logger::Verbosity::DEBUG});
    std::this_thread::sleep_for(2s);
    logger.info("Updating period to 100ms");
    timer.set_period(100ms);

Timer AdvancedConfig Example

    auto timer_fn = []() {
      static size_t iterations{0};
      fmt::print("[{:.3f}] #iterations = {}\n", elapsed(), iterations);
      iterations++;
      // we don't want to stop, so return false
      return false;
    };
    auto timer = espp::Timer({.period = 500ms,
                              .callback = timer_fn,
                              .task_config =
                                  {
                                      .name = "Advanced Config Timer",
                                      .stack_size_bytes = 4096,
                                      .priority = 10,
                                      .core_id = 1,
                                  },
                              .log_level = espp::Logger::Verbosity::DEBUG});

Note

The timer uses a task to run in the background, so the timer callback function will be called in the context of the task. The timer callback function should not block for a long time because it will block the task. If the timer callback function blocks for a long time, then the timer will not be able to keep up with the period.

Public Types

typedef std::function<bool()> callback_fn

The callback function type. Return true to cancel the timer.

Public Functions

explicit Timer(const Config &config)

Construct a new Timer object.

Parameters

config – The configuration for the timer.

explicit Timer(const AdvancedConfig &config)

Construct a new Timer object.

Parameters

config – The configuration for the timer.

~Timer()

Destroy the Timer object.

Cancels the timer if it is running.

void start()

Start the timer.

Starts the timer. Does nothing if the timer is already running.

void start(const std::chrono::duration<float> &delay)

Start the timer with a delay.

Starts the timer with a delay. If the timer is already running, this will cancel the timer and start it again with the new delay. If the timer is not running, this will start the timer with the delay. Overwrites any previous delay that might have been set.

Parameters

delay – The delay before the first execution of the timer callback.

void stop()

Stop the timer, same as cancel().

Stops the timer, same as cancel().

void cancel()

Cancel the timer.

Cancels the timer.

bool start_watchdog()

Start the task watchdog for the timer.

See also

stop_watchdog()

Note

This function is only available on ESP

Note

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

Returns

true if the watchdog was started, false otherwise.

bool stop_watchdog()

Stop the task watchdog for the timer.

See also

start_watchdog()

Note

This function is only available on ESP

Note

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

Returns

true if the watchdog was stopped, false otherwise.

void set_period(const std::chrono::duration<float> &period)

Set the period of the timer.

Sets the period of the timer.

Note

If the period is 0, the timer will run once.

Note

If the period is negative, the period will not be set / updated.

Note

If the timer is running, the period will be updated after the current period has elapsed.

Parameters

period – The period of the timer.

bool is_running() const

Check if the timer is running.

Checks if the timer is running.

Returns

true if the timer is running, false otherwise.

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters

rate_limit – The rate limit to use for the logger

struct AdvancedConfig

Advanced configuration for the timer.

Public Members

std::chrono::duration<float> period

The period of the timer. If 0, the timer callback will only be called once.

std::chrono::duration<float> delay = std::chrono::duration<float>(0)

The delay before the first execution of the timer callback after start() is called.

espp::Timer::callback_fn callback

The callback function to call when the timer expires.

bool auto_start = {true}

If true, the timer will start automatically when constructed.

espp::Task::BaseConfig task_config

The task configuration for the timer.

espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN

The log level for the timer.

struct Config

The configuration for the timer.

Public Members

std::string_view name

The name of the timer.

std::chrono::duration<float> period

The period of the timer. If 0, the timer callback will only be called once.

std::chrono::duration<float> delay = std::chrono::duration<float>(0)

The delay before the first execution of the timer callback after start() is called.

espp::Timer::callback_fn callback

The callback function to call when the timer expires.

bool auto_start = {true}

If true, the timer will start automatically when constructed.

size_t stack_size_bytes = {4096}

The stack size of the task that runs the timer.

size_t priority = {0}

Priority of the timer, 0 is lowest priority on ESP / FreeRTOS.

int core_id = {-1}

Core ID of the timer, -1 means it is not pinned to any core.

espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN

The log level for the timer.

High Resolution Timer

The HighResolutionTimer component provides an esp-idf specific API to create managed high resolution timer objects using the esp_timer API. The timer can be started, stopped, and restarted, and it can be configured as a one-shot timer or a periodic timer.

API Reference

Header File

Classes

class HighResolutionTimer : public espp::BaseComponent

High resolution timer This class provides a high resolution timer using the ESP-IDF esp_timer API. The timer can be started in oneshot or periodic mode. The timer period can be set and queried. The timer can be started, stopped, and restarted. The timer can be queried to check if it is running.

High Resolution Timer Example

    logger.set_rate_limit(100ms);
    auto timer_fn = [&]() {
      static size_t iterations{0};
      iterations++;
      logger.info_rate_limited("High resolution timer callback: {}", iterations);
      // we don't want to stop, so return false
      return false;
    };
    auto high_resolution_timer =
        espp::HighResolutionTimer({.name = "High Resolution Timer",
                                   .callback = timer_fn,
                                   .log_level = espp::Logger::Verbosity::DEBUG});
    uint64_t period_us = 100;
    bool started = high_resolution_timer.start(period_us);
    logger.info("High resolution timer started: {}", started);

    std::this_thread::sleep_for(500ms);
    logger.info("Updating period to 100ms");
    period_us = 1000 * 100;
    high_resolution_timer.set_period(period_us);
    logger.info("Periodic timer period: {}us", high_resolution_timer.get_period());

    // NOTE: only if CONFIG_ESP_TIMER_PROFILING is enabled will this show more
    //       than address, period and alarm.
    esp_timer_dump(stdout); // dump timer stats

    std::this_thread::sleep_for(500ms);
    logger.info("High resolution timer is running: {}", high_resolution_timer.is_running());
    logger.info("Stopping timer");
    high_resolution_timer.stop();

    std::this_thread::sleep_for(500ms);
    logger.info("Starting oneshot to expire in 100ms");
    started = high_resolution_timer.oneshot(period_us);
    logger.info("Oneshot timer started: {}", started);
    logger.info("Oneshot timer expiry: {}us", high_resolution_timer.get_period());

High Resolution Timer Watchdog Example

    logger.set_rate_limit(100ms);
    auto timer_fn = [&]() {
      static size_t iterations{0};
      iterations++;
      logger.info_rate_limited("High resolution timer callback: {}", iterations);
      // we don't want to stop, so return false
      return false;
    };
    auto high_resolution_timer =
        espp::HighResolutionTimer({.name = "High Resolution Timer 1",
                                   .callback = timer_fn,
                                   .log_level = espp::Logger::Verbosity::DEBUG});
    uint64_t period_us = 100;
    bool started = high_resolution_timer.start(period_us);
    logger.info("High resolution timer 1 started: {}", started);

    // make another HighResolutionTimer
    auto timer2_fn = [&]() {
      // sleep here to ensure watchdog triggers
      std::this_thread::sleep_for(350ms);
      // we don't want to stop, so return false
      return false;
    };
    auto high_resolution_timer2 =
        espp::HighResolutionTimer({.name = "High Resolution Timer 2",
                                   .callback = timer2_fn,
                                   .log_level = espp::Logger::Verbosity::DEBUG});

    // configure the task watchdog
    static constexpr bool panic_on_watchdog_timeout = false;
    espp::Task::configure_task_watchdog(300ms, panic_on_watchdog_timeout);

    // start the watchdog timer for this timer
    high_resolution_timer2.start_watchdog();

    // ensure we can run the watchdog on a oneshot timer which is started after
    // we start the watchdog
    period_us = 1000 * 100;
    started = high_resolution_timer2.oneshot(period_us);
    logger.info("High resolution timer 2 started: {}", started);

    std::this_thread::sleep_for(400ms);

    std::error_code ec;
    std::string watchdog_info = espp::Task::get_watchdog_info(ec);
    if (ec) {
      fmt::print("Error getting watchdog info: {}\n", ec.message());
    } else if (!watchdog_info.empty()) {
      fmt::print("Watchdog info: {}\n", watchdog_info);
    } else {
      fmt::print("No watchdog info available\n");
    }

    // now stop the watchdog timer
    high_resolution_timer2.stop_watchdog();

    // delay some more so we can see the watchdog timer has stopped
    std::this_thread::sleep_for(500ms);

Note

Since this uses the esp-timer API, you cannot set different stack sizes for differnt timers like you can with espp::Timer and espp::Task. Instead, you may need to adjust the stack size via the menuconfig CONFIG_ESP_TIMER_TASK_STACK_SIZE.

Public Types

typedef std::function<void()> Callback

Callback type for the timer.

Public Functions

explicit HighResolutionTimer(const Config &config)

Constructor

Parameters

config – Configuration of the timer

~HighResolutionTimer()

Destructor.

bool start(uint64_t period_us = 0, bool oneshot = false)

Start the timer

Parameters
  • period_us – Period of the timer in microseconds, or timeout if oneshot is true

  • oneshot – True if the timer should be oneshot, false if periodic

Returns

True if the timer was started successfully, false otherwise

bool oneshot(uint64_t timeout_us = 0)

Start the timer in oneshot mode

Parameters

timeout_us – Timeout of the timer in microseconds

Returns

True if the timer was started successfully, false otherwise

bool periodic(uint64_t period_us = 0)

Start the timer in periodic mode

Parameters

period_us – Period of the timer in microseconds

Returns

True if the timer was started successfully, false otherwise

void stop()

Stop the timer.

bool start_watchdog()

Start the watchdog timer

Note

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

Returns

True if the watchdog timer was started successfully, false otherwise

bool stop_watchdog()

Stop the watchdog timer

Note

This function will do nothing unless CONFIG_ESP_TASK_WDT_EN is enabled in the menuconfig. Default is y (enabled).

Returns

True if the watchdog timer was stopped successfully, false otherwise

bool is_running() const

Check if the timer is running

Returns

True if the timer is running, false otherwise

bool is_oneshot() const

Is the timer oneshot?

Returns

True if the timer is a oneshot timer, false if it is perioic.

bool is_periodic() const

Is the timer periodic?

Returns

True if the timer is a periodic timer, false if it is oneshot.

void set_period(uint64_t period_us)

Set the period of the timer in microseconds

Note

This function will restart the timer if it is running

Parameters

period_us – Period of the timer in microseconds

uint64_t get_period()

Get the period of the timer in microseconds

Note

This function will return 0 if the timer is not running

Note

This function will return the period of the timer, not the remaining time

Returns

Period of the timer in microseconds

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters

rate_limit – The rate limit to use for the logger

struct Config

Configuration of the timer.

Public Members

std::string name

Name of the timer.

Callback callback = {nullptr}

Callback to be called when the timer expires.

bool skip_unhandled_events = {false}

Skip unhandled events. If true, will skip unhandled events in light sleep for periodic timers.

esp_timer_dispatch_t dispatch_method = ESP_TIMER_TASK

Dispatch method, TIMER_TASK or TIMER_ISR.

espp::Logger::Verbosity log_level = espp::Logger::Verbosity::WARN

Log level.