Re implement display
This commit is contained in:
@@ -1,59 +1,99 @@
|
||||
#pragma once
|
||||
#include "display/display.h"
|
||||
#include "lvgl.h"
|
||||
#include "esp_lvgl_port.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "esp_lcd_touch_gt911.h"
|
||||
#include "common/semaphore_guard.h"
|
||||
#include <vector>
|
||||
|
||||
// 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 {
|
||||
// forward declarations
|
||||
class EInkDisplayHandler;
|
||||
|
||||
struct RefreshArea {
|
||||
public:
|
||||
EInkDisplayHandler(EventGroupHandle_t system_event_group);
|
||||
RefreshArea(int32_t x_start, int32_t y_start, int32_t x_end, int32_t y_end)
|
||||
: x1(x_start), y1(y_start), x2(x_end), y2(y_end) { }
|
||||
int32_t x1;
|
||||
int32_t y1;
|
||||
int32_t x2;
|
||||
int32_t y2;
|
||||
};
|
||||
|
||||
class EInkDisplayHandler {
|
||||
public:
|
||||
EInkDisplayHandler();
|
||||
virtual ~EInkDisplayHandler();
|
||||
|
||||
void init();
|
||||
void start_touch_task();
|
||||
esp_err_t init_devices(EventGroupHandle_t system_event_group = nullptr);
|
||||
|
||||
|
||||
esp_err_t refresh_display(void);
|
||||
esp_err_t full_write(const uint8_t* framebuffer);
|
||||
esp_err_t partial_refresh(const uint8_t* framebuffer, const RefreshArea& area);
|
||||
esp_err_t clear_display(void);
|
||||
// Request a full refresh on next flush
|
||||
void request_full_refresh();
|
||||
void request_full_refresh(void);
|
||||
|
||||
// Check if display is busy (refreshing)
|
||||
bool is_busy() const;
|
||||
bool is_busy(void) const;
|
||||
void wait_for_idle(void) const;
|
||||
|
||||
esp_lcd_touch_handle_t get_touch_handle() const { return tp_handle_; }
|
||||
|
||||
protected:
|
||||
esp_err_t epd_write_cmd(const uint8_t cmd, uint32_t transaction_id);
|
||||
esp_err_t epd_write_data(const uint8_t data, uint32_t transaction_id);
|
||||
esp_err_t epd_write_cmd_with_data(const uint8_t cmd, std::vector<uint8_t>& data, uint32_t transaction_id);
|
||||
esp_err_t transfer_spi_data(const uint8_t* data, const size_t& length, uint32_t transaction_id);
|
||||
|
||||
private:
|
||||
// LVGL display and input device handles
|
||||
lv_display_t* _lvgl_display = nullptr;
|
||||
lv_indev_t* _lvgl_touch_indev = nullptr;
|
||||
lv_draw_buf_t* _lvgl_draw_buf = nullptr;
|
||||
|
||||
// Framebuffer
|
||||
uint8_t* _framebuffer = nullptr;
|
||||
bool _framebuffer_in_psram = false;
|
||||
esp_err_t init_display_pins_(void);
|
||||
esp_err_t epd_init_(void);
|
||||
esp_err_t init_touch_(void);
|
||||
esp_err_t dangerous_epd_write_cmd_without_lock_(const uint8_t cmd);
|
||||
esp_err_t dangerous_epd_write_data_without_lock_(const uint8_t data);
|
||||
|
||||
// Refresh tracking
|
||||
uint32_t _partial_refresh_count = 0;
|
||||
bool _force_full_refresh = false;
|
||||
SemaphoreHandle_t _refresh_mutex = nullptr;
|
||||
esp_err_t begin_transaction_(TickType_t timeout, uint32_t& out_id);
|
||||
esp_err_t end_transaction_(void);
|
||||
// given a transaction ID, wait for current transaction to complete. The transaction ID will determine if the wait is needed.
|
||||
esp_err_t wait_for_transaction_end_(TickType_t timeout, uint32_t awaiting_transaction_id, SemaphoreGuard& out_transaction_guard);
|
||||
|
||||
// Touch task
|
||||
TaskHandle_t _touch_task_handle = nullptr;
|
||||
friend class TransactionGuard;
|
||||
|
||||
// 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);
|
||||
uint32_t partial_refresh_count_ = 0;
|
||||
bool force_full_refresh_ = false;
|
||||
|
||||
// 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);
|
||||
SemaphoreHandle_t spi_mutex_ = nullptr;
|
||||
SemaphoreHandle_t spi_transaction_mutex_ = nullptr;
|
||||
SemaphoreHandle_t refresh_mutex_ = nullptr;
|
||||
uint32_t spi_transaction_id = 0; // For tracking SPI transactions
|
||||
spi_device_handle_t spi_ = nullptr;
|
||||
esp_lcd_panel_io_handle_t tp_io_handle_ = nullptr;
|
||||
esp_lcd_touch_handle_t tp_handle_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
class TransactionGuard {
|
||||
public:
|
||||
TransactionGuard(EInkDisplayHandler& handler, TickType_t timeout = portMAX_DELAY)
|
||||
: handler_(handler) { }
|
||||
~TransactionGuard() { if (transaction_id_) handler_.end_transaction_(); }
|
||||
|
||||
esp_err_t begin(TickType_t timeout = portMAX_DELAY) {
|
||||
esp_err_t err = handler_.begin_transaction_(timeout, transaction_id_);
|
||||
return err;
|
||||
}
|
||||
uint32_t transaction_id() const { return transaction_id_; }
|
||||
bool is_active() const { return transaction_id_ != 0; }
|
||||
private:
|
||||
// delete copy constructor and assignment operator
|
||||
TransactionGuard(const TransactionGuard&) = delete;
|
||||
TransactionGuard& operator=(const TransactionGuard&) = delete;
|
||||
EInkDisplayHandler& handler_;
|
||||
uint32_t transaction_id_ = 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user