diff --git a/esp/cpp/07_lcd-panel/main/display.cpp b/esp/cpp/07_lcd-panel/main/display.cpp index 6550611..55e3b1f 100644 --- a/esp/cpp/07_lcd-panel/main/display.cpp +++ b/esp/cpp/07_lcd-panel/main/display.cpp @@ -12,6 +12,9 @@ // We must use a mutex to protect it. _lock_t Display::ScopedLock::lv_lock_; +std::unordered_map + Display::TimeKeeper::managed_timers_; + Display::Display(IPanelDevice &device) : panel_(device), lv_tick_timer_(nullptr) @@ -152,15 +155,13 @@ void Display::lvgl_increase_tick(void *) } } -void Display::register_lvgl_tick_timer() // NOLINT(*-convert-member-functions-to-static) +void Display::register_lvgl_tick_timer() { ESP_LOGI(TAG, "Use esp_timer to increase LVGL tick"); const esp_timer_create_args_t lvgl_tick_timer_args = { .callback = &Display::lvgl_increase_tick, .name = "lvgl_tick" }; - esp_timer_handle_t lvgl_tick_timer = nullptr; - ESP_ERROR_CHECK(esp_timer_create(&lvgl_tick_timer_args, &lvgl_tick_timer)); - ESP_ERROR_CHECK(esp_timer_start_periodic(lvgl_tick_timer, - LVGL_TICK_PERIOD_MS * 1000)); + TimeKeeper::start_new_timer_periodic(lvgl_tick_timer_args, + LVGL_TICK_PERIOD_MS * 1000); } diff --git a/esp/cpp/07_lcd-panel/main/display.h b/esp/cpp/07_lcd-panel/main/display.h index 365afd7..5a048ee 100644 --- a/esp/cpp/07_lcd-panel/main/display.h +++ b/esp/cpp/07_lcd-panel/main/display.h @@ -5,6 +5,7 @@ #include #include +#include #include "panel.h" @@ -13,6 +14,33 @@ #define LVGL_TASK_PRIORITY 2 class Display { + struct ScopedLock { + explicit ScopedLock() { _lock_acquire(&lv_lock_); } + + ~ScopedLock() { _lock_release(&lv_lock_); } + + // LVGL library is not thread-safe, this example calls LVGL APIs from tasks. + // We must use a mutex to protect it. + static _lock_t lv_lock_; + }; + + struct Timer { + explicit Timer(esp_timer_create_args_t args) : args_(args) + { + ESP_LOGI(TAG, "Creating esp_timer with name: %s", args.name); + ESP_ERROR_CHECK(esp_timer_create(&args, &esp_timer_)); + } + + ~Timer() + { + ESP_ERROR_CHECK(esp_timer_delete(esp_timer_)); + } + + + [[maybe_unused]] esp_timer_create_args_t args_{}; + esp_timer_handle_t esp_timer_ = nullptr; + }; + public: explicit Display(IPanelDevice &device); @@ -43,6 +71,72 @@ public: [[noreturn]] static void lvgl_port_task(void *arg); + struct TimeKeeper { + using TimerHandle = Timer *; + + // Timers should only be accessed using this method. + // For this reason managed_timers_ is private. + static TimerHandle get_handle(const char *name) + { + return &managed_timers_.at(name); + } + + static TimerHandle create_timer(esp_timer_create_args_t args) + { + auto rt = managed_timers_.emplace(args.name, args); + if (!rt.second) { + ESP_LOGE(TAG, "Failed to insert timer into Display::managed_timers_"); + return nullptr; + } + return &rt.first->second; + } + + [[maybe_unused]] static void stop_timer(const char *name) + { + ESP_ERROR_CHECK(esp_timer_stop(get_handle(name)->esp_timer_)); + } + + [[maybe_unused]] static void delete_timer(const char *name) + { + managed_timers_.erase(name); + } + + [[maybe_unused]] static void + start_new_timer_periodic(esp_timer_create_args_t args, + uint64_t period) + { + start_timer_periodic(create_timer(args)->args_.name, period); + } + + [[maybe_unused]] static void start_timer_periodic(const char *name, + uint64_t period) + { + ESP_ERROR_CHECK( + esp_timer_start_periodic(get_handle(name)->esp_timer_, period)); + } + + [[maybe_unused]] static void + start_new_timer_once(esp_timer_create_args_t args, + uint64_t timeout_us) + { + start_timer_once(create_timer(args)->args_.name, timeout_us); + } + + [[maybe_unused]] static void start_timer_once(const char *name, + uint64_t timeout_us) + { + ESP_ERROR_CHECK( + esp_timer_start_once(get_handle(name)->esp_timer_, timeout_us)); + } + + // TODO start_timer_once + private: + + // Timers should only be accessed using the get_handle method. + // ~Timer() will delete the timer if called. + static std::unordered_map managed_timers_; + }; + private: void register_lvgl_tick_timer(); @@ -60,16 +154,6 @@ private: // TODO: This could be a private struct esp_timer_handle_t lv_tick_timer_; - - struct ScopedLock { - explicit ScopedLock() { _lock_acquire(&lv_lock_); } - - ~ScopedLock() { _lock_release(&lv_lock_); } - - // LVGL library is not thread-safe, this example calls LVGL APIs from tasks. - // We must use a mutex to protect it. - static _lock_t lv_lock_; - }; }; #endif // DISPLAY_H