101 lines
3.0 KiB
C++
101 lines
3.0 KiB
C++
#pragma once
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/semphr.h"
|
|
#include "esp_lcd_touch_gt911.h"
|
|
#include "common/semaphore_guard.h"
|
|
#include <vector>
|
|
#include <atomic>
|
|
#include "epd_handler.h"
|
|
|
|
// Refresh mode configuration
|
|
#define DISPLAY_WIDTH 800
|
|
#define DISPLAY_HEIGHT 480
|
|
|
|
// forward declarations
|
|
class EInkDisplayHandler;
|
|
|
|
struct RefreshArea {
|
|
public:
|
|
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;
|
|
// reset to empty area
|
|
void reset() {
|
|
x1 = y1 = x2 = y2 = 0;
|
|
}
|
|
// expand area to include another area
|
|
void expand_to_include(const RefreshArea& other) {
|
|
expand_to_include(other.x1, other.y1, other.x2, other.y2);
|
|
}
|
|
void expand_to_include(int32_t x1, int32_t y1, int32_t x2, int32_t y2) {
|
|
const bool force_update = is_empty();
|
|
if (x1 < this->x1 || force_update) this->x1 = x1;
|
|
if (y1 < this->y1 || force_update) this->y1 = y1;
|
|
if (x2 > this->x2 || force_update) this->x2 = x2;
|
|
if (y2 > this->y2 || force_update) this->y2 = y2;
|
|
}
|
|
bool is_empty() const {
|
|
return (x1 == 0 && y1 == 0 && x2 == 0 && y2 == 0);
|
|
}
|
|
uint32_t area() const {
|
|
if (is_empty()) return 0;
|
|
return (x2 - x1 + 1) * (y2 - y1 + 1);
|
|
}
|
|
};
|
|
|
|
class EInkDisplayHandler {
|
|
public:
|
|
EInkDisplayHandler();
|
|
virtual ~EInkDisplayHandler();
|
|
|
|
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, const bool white_basemap = true);
|
|
esp_err_t partial_refresh(const uint8_t* framebuffer, const RefreshArea& area, const bool is_last_partial_update = true);
|
|
esp_err_t clear_display(void);
|
|
esp_err_t deep_sleep_display(void);
|
|
// Request a full refresh on next flush
|
|
void request_full_refresh(void);
|
|
|
|
bool is_busy() {
|
|
return epd_handler_.is_busy();
|
|
}
|
|
|
|
esp_lcd_touch_handle_t get_touch_handle() const { return tp_handle_; }
|
|
|
|
private:
|
|
|
|
esp_err_t init_display_pins_(void);
|
|
esp_err_t epd_init_internal_(uint32_t transaction_id); // full fast refresh init
|
|
esp_err_t epd_init_partial_internal_(uint32_t transaction_id); // partial refresh init (within existing transaction)
|
|
esp_err_t init_touch_(void);
|
|
|
|
// write to the internal draw buffer
|
|
void write_to_buffer_(const uint8_t* src, const RefreshArea& area);
|
|
// write the internal draw buffer to the display's old sram
|
|
esp_err_t refresh_old_buffer_(uint32_t transaction_id);
|
|
|
|
|
|
EPDHandler epd_handler_;
|
|
uint32_t partial_refresh_count_ = 0;
|
|
bool force_full_refresh_ = false;
|
|
std::atomic<bool> is_deep_sleep_ { false };
|
|
|
|
SemaphoreHandle_t refresh_mutex_ = nullptr;
|
|
esp_lcd_panel_io_handle_t tp_io_handle_ = nullptr;
|
|
esp_lcd_touch_handle_t tp_handle_ = nullptr;
|
|
|
|
// Display buffers (1=black, 0=white)
|
|
uint8_t* draw_buffer_ = nullptr;
|
|
uint8_t* old_buffer_ = nullptr;
|
|
uint8_t* black_data_ = nullptr; // All 0xFF (black pattern)
|
|
uint8_t* white_data_ = nullptr; // All 0x00 (white pattern)
|
|
RefreshArea refresh_area_ = { 0, 0, 0, 0 };
|
|
};
|
|
|