#pragma once #include "display/display.h" #include "lvgl.h" #include "esp_lvgl_port.h" #include "freertos/semphr.h" // Refresh mode configuration #define PARTIAL_REFRESH_THRESHOLD 10 // Full refresh every N partial refreshes #define DISPLAY_WIDTH 800 #define DISPLAY_HEIGHT 480 #define DISPLAY_BUFFER_SIZE ((DISPLAY_WIDTH * DISPLAY_HEIGHT) / 8) // 1-bit per pixel class EInkDisplayHandler : public DisplayHandler { public: EInkDisplayHandler(EventGroupHandle_t system_event_group); virtual ~EInkDisplayHandler(); void init(); void start_touch_task(); // Request a full refresh on next flush void request_full_refresh(); // Check if display is busy (refreshing) bool is_busy() const; private: // LVGL display and input device handles lv_display_t* _lvgl_display = nullptr; lv_indev_t* _lvgl_touch_indev = nullptr; // Framebuffer uint8_t* _framebuffer = nullptr; bool _framebuffer_in_psram = false; // Refresh tracking uint32_t _partial_refresh_count = 0; bool _force_full_refresh = false; SemaphoreHandle_t _refresh_mutex = nullptr; // Touch task TaskHandle_t _touch_task_handle = nullptr; // LVGL callbacks static void _lvgl_flush_cb(lv_display_t* disp, const lv_area_t* area, uint8_t* px_map); static void _lvgl_touch_read_cb(lv_indev_t* indev, lv_indev_data_t* data); // Display operations void _perform_full_refresh(const uint8_t* framebuffer); void _perform_partial_refresh(const uint8_t* framebuffer); void _wait_for_busy(); // Touch task static void _touch_task(void* param); // Helper to convert LVGL 1-bit buffer to e-paper format void _convert_buffer_to_epaper(const uint8_t* lvgl_buf, uint8_t* epd_buf, size_t size); };