Make TimeKeeper a static member of Display.

This commit is contained in:
Shaun Reed 2025-02-16 09:12:24 -05:00
parent 9140ba5fb4
commit 74404b1a44
2 changed files with 105 additions and 97 deletions

View File

@ -12,12 +12,12 @@
// We must use a mutex to protect it. // We must use a mutex to protect it.
_lock_t Display::ScopedLock::lv_lock_; _lock_t Display::ScopedLock::lv_lock_;
std::unordered_map<const char *, Display::Timer> // Static TimeKeeper for managing ESP timers across all displays.
Display::TimeKeeper::managed_timers_; Display::TimeKeeper Display::timers_;
Display::Display(IPanelDevice &device) : Display::Display(IPanelDevice &device) :
panel_(device), panel_(device),
lv_tick_timer_(nullptr) lv_buf_(nullptr)
{ {
if (!lv_is_initialized()) { if (!lv_is_initialized()) {
ESP_LOGI(TAG, "Initialize LVGL"); ESP_LOGI(TAG, "Initialize LVGL");
@ -29,30 +29,8 @@ Display::Display(IPanelDevice &device) :
// associate the i2c panel handle to the display // associate the i2c panel handle to the display
lv_display_set_user_data(lv_display_, panel_.esp_panel_); lv_display_set_user_data(lv_display_, panel_.esp_panel_);
// Create draw buffer. register_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_));
register_lvgl_tick_timer(); register_lvgl_tick_timer();
// TODO: What is this // 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() void Display::register_lvgl_tick_timer()
{ {
ESP_LOGI(TAG, "Use esp_timer to increase LVGL tick"); 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, .callback = &Display::lvgl_increase_tick,
.name = "lvgl_tick" .name = "lvgl_tick"
}; };
TimeKeeper::start_new_timer_periodic(lvgl_tick_timer_args, timers_.start_new_timer_periodic(esp_timer_args, LVGL_TICK_PERIOD_MS * 1000);
LVGL_TICK_PERIOD_MS * 1000);
} }

View File

@ -41,6 +41,73 @@ class Display {
esp_timer_handle_t esp_timer_ = nullptr; 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<const char *, Timer> managed_timers_;
};
public: public:
explicit Display(IPanelDevice &device); explicit Display(IPanelDevice &device);
@ -71,73 +138,12 @@ public:
[[noreturn]] static void lvgl_port_task(void *arg); [[noreturn]] static void lvgl_port_task(void *arg);
struct TimeKeeper { // Public static TimeKeeper for managing ESP timers across all displays.
using TimerHandle = Timer *; static TimeKeeper timers_;
// 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<const char *, Timer> managed_timers_;
};
private: private:
void register_draw_buffer();
void register_lvgl_tick_timer(); void register_lvgl_tick_timer();
Panel panel_; Panel panel_;
@ -151,9 +157,6 @@ private:
// @sa Display::set_text // @sa Display::set_text
// @sa lv_display_get_screen_active // @sa lv_display_get_screen_active
std::unordered_map<const char *, lv_obj_t *> lv_objects_; std::unordered_map<const char *, lv_obj_t *> lv_objects_;
// TODO: This could be a private struct
esp_timer_handle_t lv_tick_timer_;
}; };
#endif // DISPLAY_H #endif // DISPLAY_H