diff --git a/esp/cpp/07_lcd-panel/main/display.cpp b/esp/cpp/07_lcd-panel/main/display.cpp index 55e3b1f..7c4b5aa 100644 --- a/esp/cpp/07_lcd-panel/main/display.cpp +++ b/esp/cpp/07_lcd-panel/main/display.cpp @@ -12,12 +12,12 @@ // We must use a mutex to protect it. _lock_t Display::ScopedLock::lv_lock_; -std::unordered_map - Display::TimeKeeper::managed_timers_; +// Static TimeKeeper for managing ESP timers across all displays. +Display::TimeKeeper Display::timers_; Display::Display(IPanelDevice &device) : panel_(device), - lv_tick_timer_(nullptr) + lv_buf_(nullptr) { if (!lv_is_initialized()) { ESP_LOGI(TAG, "Initialize LVGL"); @@ -29,30 +29,8 @@ Display::Display(IPanelDevice &device) : // associate the i2c panel handle to the display lv_display_set_user_data(lv_display_, panel_.esp_panel_); - // Create draw buffer. - ESP_LOGI(TAG, "Allocate separate LVGL draw buffers"); - lv_buf_ = heap_caps_calloc(1, panel_.device_->lv_buf_size_, - MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); - assert(lv_buf_); + register_draw_buffer(); - ESP_LOGI(TAG, "Set LVGL draw buffers"); - // Color format must be set first, LVGL9 suooprt new monochromatic format. - lv_display_set_color_format(lv_display_, LV_COLOR_FORMAT_I1); - lv_display_set_buffers(lv_display_, lv_buf_, nullptr, - panel_.device_->lv_buf_size_, - LV_DISPLAY_RENDER_MODE_FULL); - lv_display_set_rotation(lv_display_, LV_DISPLAY_ROTATION_0); - - ESP_LOGI(TAG, "Set LVGL callback for flushing to the display"); - lv_display_set_flush_cb(lv_display_, Display::lvgl_flush_cb); - - ESP_LOGI(TAG, "Register io panel callback for LVGL flush ready notification"); - const esp_lcd_panel_io_callbacks_t cbs = { - .on_color_trans_done = Display::lvgl_flush_ready, - }; - ESP_ERROR_CHECK( - esp_lcd_panel_io_register_event_callbacks(panel_.esp_io_, &cbs, - lv_display_)); register_lvgl_tick_timer(); // TODO: What is this @@ -155,13 +133,40 @@ void Display::lvgl_increase_tick(void *) } } +void Display::register_draw_buffer() +{ + // Create draw buffer. + ESP_LOGI(TAG, "Allocate separate LVGL draw buffers"); + lv_buf_ = heap_caps_calloc(1, panel_.device_->lv_buf_size_, + MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); + assert(lv_buf_); + + ESP_LOGI(TAG, "Set LVGL draw buffers"); + // Color format must be set first, LVGL9 suooprt new monochromatic format. + lv_display_set_color_format(lv_display_, LV_COLOR_FORMAT_I1); + lv_display_set_buffers(lv_display_, lv_buf_, nullptr, + panel_.device_->lv_buf_size_, + LV_DISPLAY_RENDER_MODE_FULL); + lv_display_set_rotation(lv_display_, LV_DISPLAY_ROTATION_0); + + ESP_LOGI(TAG, "Set LVGL callback for flushing to the display"); + lv_display_set_flush_cb(lv_display_, Display::lvgl_flush_cb); + + ESP_LOGI(TAG, "Register io panel callback for LVGL flush ready notification"); + const esp_lcd_panel_io_callbacks_t cbs = { + .on_color_trans_done = Display::lvgl_flush_ready, + }; + ESP_ERROR_CHECK( + esp_lcd_panel_io_register_event_callbacks(panel_.esp_io_, &cbs, + lv_display_)); +} + 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 = { + const esp_timer_create_args_t esp_timer_args = { .callback = &Display::lvgl_increase_tick, .name = "lvgl_tick" }; - TimeKeeper::start_new_timer_periodic(lvgl_tick_timer_args, - LVGL_TICK_PERIOD_MS * 1000); + timers_.start_new_timer_periodic(esp_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 5a048ee..cd9f13a 100644 --- a/esp/cpp/07_lcd-panel/main/display.h +++ b/esp/cpp/07_lcd-panel/main/display.h @@ -41,6 +41,73 @@ class Display { esp_timer_handle_t esp_timer_ = nullptr; }; + struct TimeKeeper { + using TimerHandle = Timer *; + + // Timers should only be accessed using this method. + // For this reason managed_timers_ is private. + TimerHandle get_handle(const char *name) + { + return &managed_timers_.at(name); + } + + TimerHandle operator[](const char * name) { return get_handle(name); } + + 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]] void stop_timer(const char *name) + { + ESP_ERROR_CHECK(esp_timer_stop(get_handle(name)->esp_timer_)); + } + + [[maybe_unused]] void delete_timer(const char *name) + { + managed_timers_.erase(name); + } + + [[maybe_unused]] 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]] 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]] 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]] 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)); + } + + private: + + // Timers should only be accessed using the get_handle method. + // ~Timer() will delete the timer if called. + std::unordered_map managed_timers_; + }; + public: explicit Display(IPanelDevice &device); @@ -71,73 +138,12 @@ 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_; - }; + // Public static TimeKeeper for managing ESP timers across all displays. + static TimeKeeper timers_; private: + void register_draw_buffer(); + void register_lvgl_tick_timer(); Panel panel_; @@ -151,9 +157,6 @@ private: // @sa Display::set_text // @sa lv_display_get_screen_active std::unordered_map lv_objects_; - - // TODO: This could be a private struct - esp_timer_handle_t lv_tick_timer_; }; #endif // DISPLAY_H