Tasmota/lib/lib_display/UDisplay/uDisplay_RGB_panel.cpp

117 lines
3.7 KiB
C++

// ======================================================
// panel/uDisplay_rgb_panel.cpp - RGB Panel Implementation
// ======================================================
#include "uDisplay_RGB_panel.h"
#if SOC_LCD_RGB_SUPPORTED
#include <cstdint>
#include <algorithm>
#include <rom/cache.h>
RGBPanel::RGBPanel(const esp_lcd_rgb_panel_config_t *config) {
ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(config, &panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_reset(panel_handle));
ESP_ERROR_CHECK(esp_lcd_panel_init(panel_handle));
width = config->timings.h_res;
height = config->timings.v_res;
framebuffer_size = width * height * 2; // 16 bpp
void* buf = NULL;
esp_lcd_rgb_panel_get_frame_buffer(panel_handle, 1, &buf);
framebuffer = (uint16_t*)buf;
uint16_t color = random(0xffff);
ESP_ERROR_CHECK(esp_lcd_panel_draw_bitmap(panel_handle, 0, 0, 1, 1, &color));
}
RGBPanel::~RGBPanel() {
// TODO: Cleanup panel_handle if needed
}
bool RGBPanel::drawPixel(int16_t x, int16_t y, uint16_t color) {
int16_t w = width, h = height;
// Apply rotation
switch (rotation) {
case 1: std::swap(w, h); std::swap(x, y); x = w - x - 1; break;
case 2: x = w - x - 1; y = h - y - 1; break;
case 3: std::swap(w, h); std::swap(x, y); y = h - y - 1; break;
}
if ((x < 0) || (x >= w) || (y < 0) || (y >= h)) return true; // Handled (out of bounds)
framebuffer[y * w + x] = color;
framebuffer_dirty = true;
return true; // Handled by RGB panel
}
bool RGBPanel::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
for (int16_t yp = y; yp < y + h; yp++) {
uint16_t* line_start = &framebuffer[yp * width + x];
for (int16_t i = 0; i < w; i++) {
line_start[i] = color;
}
}
framebuffer_dirty = true;
return true; // Handled by RGB panel
}
bool RGBPanel::setAddrWindow(int16_t x0, int16_t y0, int16_t x1, int16_t y1) {
window_x1 = x0;
window_y1 = y0;
window_x2 = x1;
window_y2 = y1;
return true; // Handled by RGB panel
}
bool RGBPanel::pushColors(uint16_t *data, uint16_t len, bool first) {
esp_lcd_panel_draw_bitmap(panel_handle, window_x1, window_y1, window_x2, window_y2, data);
return true; // Handled by RGB panel
}
bool RGBPanel::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
uint16_t* line_start = &framebuffer[y * width + x];
for (int16_t i = 0; i < w; i++) {
line_start[i] = color;
}
CACHE_WRITEBACK_ADDR((uint32_t)line_start, w * 2);
return true; // Handled by RGB panel
}
bool RGBPanel::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
for (int16_t j = 0; j < h; j++) {
framebuffer[(y + j) * width + x] = color;
}
CACHE_WRITEBACK_ADDR((uint32_t)&framebuffer[y * width + x], h * 2);
return true; // Handled by RGB panel
}
bool RGBPanel::displayOnff(int8_t on) {
esp_lcd_panel_disp_on_off(panel_handle, on != 0);
return false; // bpanel is controlled from display class
}
bool RGBPanel::invertDisplay(bool invert) {
// TODO: Not supported by RGB panels in ESP-IDF API
return false; // Not handled - let uDisplay handle if possible
}
bool RGBPanel::setRotation(uint8_t rotation) {
this->rotation = rotation & 3;
esp_lcd_panel_mirror(panel_handle, rotation == 1 || rotation == 2, rotation & 2);
esp_lcd_panel_swap_xy(panel_handle, rotation & 1);
return true; // Handled by RGB panel
}
bool RGBPanel::updateFrame() {
if (!framebuffer_dirty) {
return true;
}
CACHE_WRITEBACK_ADDR((uint32_t)framebuffer, framebuffer_size); //KISS and fast enough!
framebuffer_dirty = false;
return true; // Handled (no-op is still handled)
}
#endif // #if SOC_LCD_RGB_SUPPORTED