diff --git a/main/display/display.h b/main/display/display.h index 729a6ee..dcffdf2 100644 --- a/main/display/display.h +++ b/main/display/display.h @@ -12,18 +12,22 @@ public: DisplayHandler( EventGroupHandle_t system_event_group ) : _system_event_group(system_event_group) { } - ~DisplayHandler(); - + virtual ~DisplayHandler(); + // required to be called by inheriting class after SPI device is created // set set_display_ready to false if further initialization is needed before marking display ready - void init_devices(bool set_display_ready = true); + virtual void init_devices(bool set_display_ready = true); + +protected: + // Allow derived classes to access touch handle + esp_lcd_touch_handle_t get_touch_handle() const { return _tp_handle; } void epd_write_cmd(uint8_t cmd); void epd_write_data(uint8_t data); void epd_write_cmd_with_data(uint8_t cmd, const uint8_t* data, size_t data_len); -private: +protected: SemaphoreHandle_t _spi_mutex = xSemaphoreCreateMutex(); spi_device_handle_t _spi = nullptr; EventGroupHandle_t _system_event_group = nullptr; diff --git a/main/display/eink_display_handler.h b/main/display/eink_display_handler.h new file mode 100644 index 0000000..4c5b53a --- /dev/null +++ b/main/display/eink_display_handler.h @@ -0,0 +1,58 @@ +#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); +};