idfxx 1.0.0
Modern C++23 components for ESP-IDF
Loading...
Searching...
No Matches
timer.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 Chris Leishman
3
4#pragma once
5
20#include <idfxx/error>
21
22#include <algorithm>
23#include <chrono>
24#include <esp_timer.h>
25#include <functional>
26#include <memory>
27#include <string>
28
29namespace idfxx {
30
41class timer {
42public:
50 struct clock {
51 using rep = int64_t;
52 using period = std::micro;
53 using duration = std::chrono::microseconds;
54 using time_point = std::chrono::time_point<clock>;
55 static constexpr bool is_steady = true;
56
62 };
63
73 enum class dispatch_method : int {
74 task = ESP_TIMER_TASK,
75#if CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD || __DOXYGEN__
76 isr = ESP_TIMER_ISR,
77#endif
78 };
79
83 struct config {
84 std::string_view name = "";
86 bool skip_unhandled_events = false;
87 };
88
89#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
100 [[nodiscard]] explicit timer(const config& cfg, std::move_only_function<void()> callback);
101
111 [[nodiscard]] explicit timer(const config& cfg, void (*callback)(void*), void* arg);
112#endif
113
126 [[nodiscard]] static result<std::unique_ptr<timer>> make(config cfg, std::move_only_function<void()> callback);
127
140 [[nodiscard]] static result<std::unique_ptr<timer>> make(config cfg, void (*callback)(void*), void* arg);
141
142#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
167 template<typename Rep, typename Period>
168 [[nodiscard]] static std::unique_ptr<timer> start_once(
169 config cfg,
170 const std::chrono::duration<Rep, Period>& timeout,
171 std::move_only_function<void()> callback
172 ) {
173 return unwrap(try_start_once(std::move(cfg), timeout, std::move(callback)));
174 }
175
199 template<typename Rep, typename Period>
200 [[nodiscard]] static std::unique_ptr<timer>
201 start_once(config cfg, const std::chrono::duration<Rep, Period>& timeout, void (*callback)(void*), void* arg) {
202 return unwrap(try_start_once(std::move(cfg), timeout, callback, arg));
203 }
204
227 [[nodiscard]] static std::unique_ptr<timer>
228 start_once(config cfg, clock::time_point time, std::move_only_function<void()> callback) {
229 return unwrap(try_start_once(std::move(cfg), time, std::move(callback)));
230 }
231
253 [[nodiscard]] static std::unique_ptr<timer>
254 start_once(config cfg, clock::time_point time, void (*callback)(void*), void* arg) {
255 return unwrap(try_start_once(std::move(cfg), time, callback, arg));
256 }
257
282 template<typename Rep, typename Period>
283 [[nodiscard]] static std::unique_ptr<timer> start_periodic(
284 config cfg,
285 const std::chrono::duration<Rep, Period>& interval,
286 std::move_only_function<void()> callback
287 ) {
288 return unwrap(try_start_periodic(std::move(cfg), interval, std::move(callback)));
289 }
290
314 template<typename Rep, typename Period>
315 [[nodiscard]] static std::unique_ptr<timer>
316 start_periodic(config cfg, const std::chrono::duration<Rep, Period>& interval, void (*callback)(void*), void* arg) {
317 return unwrap(try_start_periodic(std::move(cfg), interval, callback, arg));
318 }
319#endif
320
340 template<typename Rep, typename Period>
342 config cfg,
343 const std::chrono::duration<Rep, Period>& timeout,
344 std::move_only_function<void()> callback
345 ) {
346 auto t = make(std::move(cfg), std::move(callback));
347 if (!t) {
348 return t;
349 }
350 auto r = (*t)->try_start_once(timeout);
351 if (!r) {
352 return error(r.error());
353 }
354 return t;
355 }
356
376 template<typename Rep, typename Period>
377 [[nodiscard]] static result<std::unique_ptr<timer>>
378 try_start_once(config cfg, const std::chrono::duration<Rep, Period>& timeout, void (*callback)(void*), void* arg) {
379 auto t = make(std::move(cfg), callback, arg);
380 if (!t) {
381 return t;
382 }
383 auto r = (*t)->try_start_once(timeout);
384 if (!r) {
385 return error(r.error());
386 }
387 return t;
388 }
389
408 [[nodiscard]] static result<std::unique_ptr<timer>>
409 try_start_once(config cfg, clock::time_point time, std::move_only_function<void()> callback) {
410 auto t = make(std::move(cfg), std::move(callback));
411 if (!t) {
412 return t;
413 }
414 auto r = (*t)->try_start_once(time);
415 if (!r) {
416 return error(r.error());
417 }
418 return t;
419 }
420
439 [[nodiscard]] static result<std::unique_ptr<timer>>
440 try_start_once(config cfg, clock::time_point time, void (*callback)(void*), void* arg) {
441 auto t = make(std::move(cfg), callback, arg);
442 if (!t) {
443 return t;
444 }
445 auto r = (*t)->try_start_once(time);
446 if (!r) {
447 return error(r.error());
448 }
449 return t;
450 }
451
471 template<typename Rep, typename Period>
473 config cfg,
474 const std::chrono::duration<Rep, Period>& interval,
475 std::move_only_function<void()> callback
476 ) {
477 auto t = make(std::move(cfg), std::move(callback));
478 if (!t) {
479 return t;
480 }
481 auto r = (*t)->try_start_periodic(interval);
482 if (!r) {
483 return error(r.error());
484 }
485 return t;
486 }
487
507 template<typename Rep, typename Period>
509 config cfg,
510 const std::chrono::duration<Rep, Period>& interval,
511 void (*callback)(void*),
512 void* arg
513 ) {
514 auto t = make(std::move(cfg), callback, arg);
515 if (!t) {
516 return t;
517 }
518 auto r = (*t)->try_start_periodic(interval);
519 if (!r) {
520 return error(r.error());
521 }
522 return t;
523 }
524
532
533 // Non-copyable and non-movable
534 timer(const timer&) = delete;
535 timer& operator=(const timer&) = delete;
536 timer(timer&&) = delete;
537 timer& operator=(timer&&) = delete;
538
543 [[nodiscard]] esp_timer_handle_t idf_handle() const noexcept { return _handle; }
544
549 [[nodiscard]] const std::string& name() const noexcept { return _name; }
550
551#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
561 template<typename Rep, typename Period>
562 void start_once(const std::chrono::duration<Rep, Period>& timeout) {
564 }
565
585
595 template<typename Rep, typename Period>
596 void start_periodic(const std::chrono::duration<Rep, Period>& interval) {
597 unwrap(try_start_periodic(interval));
598 }
599#endif
600
613 template<typename Rep, typename Period>
614 [[nodiscard]] result<void> try_start_once(const std::chrono::duration<Rep, Period>& timeout) {
615 return wrap(esp_timer_start_once(_handle, to_us(timeout)));
616 }
617
629 auto timeout_us = std::max(int64_t{0}, (time - clock::now()).count());
630 return wrap(esp_timer_start_once(_handle, static_cast<uint64_t>(timeout_us)));
631 }
632
651 esp_err_t try_start_once_isr(uint64_t timeout_us);
652
665 template<typename Rep, typename Period>
666 [[nodiscard]] result<void> try_start_periodic(const std::chrono::duration<Rep, Period>& interval) {
667 return wrap(esp_timer_start_periodic(_handle, to_us(interval)));
668 }
669
686 esp_err_t try_start_periodic_isr(uint64_t interval_us);
687
688#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
698 template<typename Rep, typename Period>
699 void restart(const std::chrono::duration<Rep, Period>& timeout) {
701 }
702#endif
703
716 template<typename Rep, typename Period>
717 [[nodiscard]] result<void> try_restart(const std::chrono::duration<Rep, Period>& timeout) {
718 auto err = esp_timer_restart(_handle, to_us(timeout));
719 if (err == ESP_ERR_INVALID_STATE) {
720 return wrap(esp_timer_start_once(_handle, to_us(timeout)));
721 }
722 return wrap(err);
723 }
724
741 esp_err_t try_restart_isr(uint64_t timeout_us);
742
743#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
750 void stop() { unwrap(try_stop()); }
751#endif
752
759 result<void> try_stop() { return wrap(esp_timer_stop(_handle)); }
760
772
777 [[nodiscard]] bool is_active() const noexcept { return esp_timer_is_active(_handle); }
778
788 [[nodiscard]] std::chrono::microseconds period() const noexcept {
789 uint64_t period_us = 0;
790 esp_timer_get_period(_handle, &period_us);
791 return std::chrono::microseconds{static_cast<int64_t>(period_us)};
792 }
793
803 [[nodiscard]] clock::time_point expiry_time() const noexcept {
804 uint64_t expiry;
805 if (esp_timer_get_expiry_time(_handle, &expiry) != ESP_OK) {
806 return clock::time_point::max();
807 }
808 if (expiry > static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
809 return clock::time_point::max();
810 }
811 return clock::time_point{clock::duration{static_cast<int64_t>(expiry)}};
812 }
813
822 [[nodiscard]] static clock::time_point next_alarm() {
823 return clock::time_point{clock::duration{esp_timer_get_next_alarm()}};
824 }
825
826private:
828 struct context;
830
831 explicit timer(esp_timer_handle_t handle, std::string name, context* ctx);
832 explicit timer(esp_timer_handle_t handle, std::string name);
833
834 template<typename Rep, typename Period>
835 static constexpr int64_t to_us(const std::chrono::duration<Rep, Period>& d) {
836 return std::chrono::duration_cast<std::chrono::microseconds>(d).count();
837 }
838
839 static void trampoline(void* arg);
840
841 esp_timer_handle_t _handle;
842 std::string _name;
843 context* _context = nullptr;
844};
845
// end of idfxx_timer
847
848} // namespace idfxx
Task lifecycle management.
Definition task.hpp:47
High-resolution timer with microsecond precision.
Definition timer.hpp:41
timer(const config &cfg, std::move_only_function< void()> callback)
Creates a timer with a std::move_only_function callback.
const std::string & name() const noexcept
Returns the timer name.
Definition timer.hpp:549
esp_err_t try_stop_isr()
Stops the timer (ISR-compatible).
static result< std::unique_ptr< timer > > try_start_once(config cfg, const std::chrono::duration< Rep, Period > &timeout, void(*callback)(void *), void *arg)
Creates and starts a one-shot timer with a raw function pointer callback.
Definition timer.hpp:378
static result< std::unique_ptr< timer > > make(config cfg, void(*callback)(void *), void *arg)
Creates a timer with a raw function pointer callback.
static clock::time_point next_alarm()
Returns the time of the next scheduled timer event.
Definition timer.hpp:822
result< void > try_start_once(const std::chrono::duration< Rep, Period > &timeout)
Starts the timer as a one-shot timer.
Definition timer.hpp:614
std::chrono::microseconds period() const noexcept
Returns the period of a periodic timer.
Definition timer.hpp:788
void start_once(clock::time_point time)
Starts the timer as a one-shot timer at an absolute time.
Definition timer.hpp:584
static std::unique_ptr< timer > start_once(config cfg, const std::chrono::duration< Rep, Period > &timeout, void(*callback)(void *), void *arg)
Creates and starts a one-shot timer with a raw function pointer callback.
Definition timer.hpp:201
static result< std::unique_ptr< timer > > try_start_once(config cfg, clock::time_point time, std::move_only_function< void()> callback)
Creates and starts a one-shot timer at an absolute time with a std::move_only_function callback.
Definition timer.hpp:409
timer(const timer &)=delete
static std::unique_ptr< timer > start_once(config cfg, clock::time_point time, std::move_only_function< void()> callback)
Creates and starts a one-shot timer at an absolute time with a std::move_only_function callback.
Definition timer.hpp:228
clock::time_point expiry_time() const noexcept
Returns the absolute expiry time for a one-shot timer.
Definition timer.hpp:803
static result< std::unique_ptr< timer > > try_start_periodic(config cfg, const std::chrono::duration< Rep, Period > &interval, std::move_only_function< void()> callback)
Creates and starts a periodic timer with a std::move_only_function callback.
Definition timer.hpp:472
timer(timer &&)=delete
result< void > try_start_once(clock::time_point time)
Starts the timer as a one-shot timer at an absolute time.
Definition timer.hpp:628
esp_err_t try_restart_isr(uint64_t timeout_us)
Restarts the timer with a new timeout (ISR-compatible).
esp_err_t try_start_periodic_isr(uint64_t interval_us)
Starts the timer as a periodic timer (ISR-compatible).
esp_err_t try_start_once_isr(uint64_t timeout_us)
Starts the timer as a one-shot timer (ISR-compatible).
void start_periodic(const std::chrono::duration< Rep, Period > &interval)
Starts the timer as a periodic timer.
Definition timer.hpp:596
static std::unique_ptr< timer > start_periodic(config cfg, const std::chrono::duration< Rep, Period > &interval, void(*callback)(void *), void *arg)
Creates and starts a periodic timer with a raw function pointer callback.
Definition timer.hpp:316
void start_once(const std::chrono::duration< Rep, Period > &timeout)
Starts the timer as a one-shot timer.
Definition timer.hpp:562
esp_timer_handle_t idf_handle() const noexcept
Returns the underlying ESP-IDF timer handle.
Definition timer.hpp:543
static std::unique_ptr< timer > start_once(config cfg, const std::chrono::duration< Rep, Period > &timeout, std::move_only_function< void()> callback)
Creates and starts a one-shot timer with a std::move_only_function callback.
Definition timer.hpp:168
static result< std::unique_ptr< timer > > try_start_once(config cfg, clock::time_point time, void(*callback)(void *), void *arg)
Creates and starts a one-shot timer at an absolute time with a raw function pointer callback.
Definition timer.hpp:440
result< void > try_stop()
Stops the timer.
Definition timer.hpp:759
static std::unique_ptr< timer > start_periodic(config cfg, const std::chrono::duration< Rep, Period > &interval, std::move_only_function< void()> callback)
Creates and starts a periodic timer with a std::move_only_function callback.
Definition timer.hpp:283
bool is_active() const noexcept
Checks if the timer is currently running.
Definition timer.hpp:777
void stop()
Stops the timer.
Definition timer.hpp:750
void restart(const std::chrono::duration< Rep, Period > &timeout)
Restarts the timer with a new timeout.
Definition timer.hpp:699
static std::unique_ptr< timer > start_once(config cfg, clock::time_point time, void(*callback)(void *), void *arg)
Creates and starts a one-shot timer at an absolute time with a raw function pointer callback.
Definition timer.hpp:254
timer & operator=(timer &&)=delete
timer(const config &cfg, void(*callback)(void *), void *arg)
Creates a timer with a raw function pointer callback.
timer & operator=(const timer &)=delete
static result< std::unique_ptr< timer > > try_start_periodic(config cfg, const std::chrono::duration< Rep, Period > &interval, void(*callback)(void *), void *arg)
Creates and starts a periodic timer with a raw function pointer callback.
Definition timer.hpp:508
result< void > try_start_periodic(const std::chrono::duration< Rep, Period > &interval)
Starts the timer as a periodic timer.
Definition timer.hpp:666
result< void > try_restart(const std::chrono::duration< Rep, Period > &timeout)
Restarts the timer with a new timeout.
Definition timer.hpp:717
static result< std::unique_ptr< timer > > make(config cfg, std::move_only_function< void()> callback)
Creates a timer with a std::move_only_function callback.
~timer()
Destroys the timer.
static result< std::unique_ptr< timer > > try_start_once(config cfg, const std::chrono::duration< Rep, Period > &timeout, std::move_only_function< void()> callback)
Creates and starts a one-shot timer with a std::move_only_function callback.
Definition timer.hpp:341
dispatch_method
Callback dispatch type.
Definition timer.hpp:73
@ task
Callback runs in high-priority timer task (default)
int esp_err_t
Definition error.hpp:32
constexpr std::unexpected< std::error_code > error(E e) noexcept
Creates an unexpected error from an error code enum.
Definition error.hpp:142
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
Definition error.hpp:237
@ timeout
Operation timed out.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
Definition error.hpp:118
result< void > wrap(esp_err_t e)
Wraps an esp_err_t into a result<void>.
Definition error.hpp:216
Monotonic clock based on boot time.
Definition timer.hpp:50
std::micro period
Definition timer.hpp:52
static constexpr bool is_steady
Definition timer.hpp:55
std::chrono::time_point< clock > time_point
Definition timer.hpp:54
static time_point now() noexcept
Returns the current time.
Definition timer.hpp:61
std::chrono::microseconds duration
Definition timer.hpp:53
Timer configuration parameters.
Definition timer.hpp:83
bool skip_unhandled_events
Skip events if callback busy.
Definition timer.hpp:86
enum dispatch_method dispatch
Callback dispatch type.
Definition timer.hpp:85
std::string_view name
Timer name for debugging.
Definition timer.hpp:84