mirror of
https://github.com/ratspeak/ratdeck.git
synced 2026-08-15 15:20:13 +00:00
Display: switch pushPixelsDMA to blocking pushPixels to prevent SPI bus contention between the display and SX1262 radio on the shared FSPI bus. LXMF: add opportunistic-first delivery with background link upgrade. First message to a peer sends immediately via opportunistic packet. A link is established in the background; subsequent messages use the link when active (prepending dest_hash for Python DIRECT format), falling back to opportunistic otherwise. No user-facing delay.
76 lines
2.3 KiB
C++
76 lines
2.3 KiB
C++
#include "Display.h"
|
|
#include <lvgl.h>
|
|
|
|
// Double-buffered 10-line strips in PSRAM for DMA flush
|
|
static lv_color_t* s_buf1 = nullptr;
|
|
static lv_color_t* s_buf2 = nullptr;
|
|
static LGFX_TDeck* s_gfx = nullptr;
|
|
|
|
static void lvgl_flush_cb(lv_disp_drv_t* drv, const lv_area_t* area, lv_color_t* color_p) {
|
|
uint32_t w = area->x2 - area->x1 + 1;
|
|
uint32_t h = area->y2 - area->y1 + 1;
|
|
s_gfx->startWrite();
|
|
s_gfx->setAddrWindow(area->x1, area->y1, w, h);
|
|
// Blocking pushPixels prevents SPI bus contention with SX1262 radio on shared FSPI bus
|
|
s_gfx->pushPixels((lgfx::swap565_t*)&color_p->full, w * h);
|
|
s_gfx->endWrite();
|
|
lv_disp_flush_ready(drv);
|
|
}
|
|
|
|
bool Display::begin() {
|
|
_gfx.init();
|
|
_gfx.setRotation(1); // Landscape: 320x240
|
|
_gfx.setBrightness(128);
|
|
_gfx.fillScreen(TFT_BLACK);
|
|
|
|
Serial.printf("[DISPLAY] Initialized: %dx%d (rotation=1, LovyanGFX direct)\n",
|
|
_gfx.width(), _gfx.height());
|
|
|
|
return true;
|
|
}
|
|
|
|
void Display::beginLVGL() {
|
|
s_gfx = &_gfx;
|
|
|
|
lv_init();
|
|
|
|
// Allocate double-buffered 20-line strips in PSRAM (halves DMA flush ops per redraw)
|
|
const uint32_t bufSize = 320 * 20;
|
|
s_buf1 = (lv_color_t*)heap_caps_malloc(bufSize * sizeof(lv_color_t), MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
|
|
s_buf2 = (lv_color_t*)heap_caps_malloc(bufSize * sizeof(lv_color_t), MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
|
|
|
|
// Fall back to PSRAM if DMA-capable memory not available
|
|
if (!s_buf1) s_buf1 = (lv_color_t*)ps_malloc(bufSize * sizeof(lv_color_t));
|
|
if (!s_buf2) s_buf2 = (lv_color_t*)ps_malloc(bufSize * sizeof(lv_color_t));
|
|
|
|
if (!s_buf1 || !s_buf2) {
|
|
Serial.println("[LVGL] FATAL: buffer allocation failed!");
|
|
return;
|
|
}
|
|
|
|
static lv_disp_draw_buf_t draw_buf;
|
|
lv_disp_draw_buf_init(&draw_buf, s_buf1, s_buf2, bufSize);
|
|
|
|
static lv_disp_drv_t disp_drv;
|
|
lv_disp_drv_init(&disp_drv);
|
|
disp_drv.hor_res = 320;
|
|
disp_drv.ver_res = 240;
|
|
disp_drv.flush_cb = lvgl_flush_cb;
|
|
disp_drv.draw_buf = &draw_buf;
|
|
lv_disp_drv_register(&disp_drv);
|
|
|
|
Serial.println("[LVGL] Display driver registered (320x240, double-buffered 20-line DMA)");
|
|
}
|
|
|
|
void Display::setBrightness(uint8_t level) {
|
|
_gfx.setBrightness(level);
|
|
}
|
|
|
|
void Display::sleep() {
|
|
_gfx.sleep();
|
|
}
|
|
|
|
void Display::wakeup() {
|
|
_gfx.wakeup();
|
|
}
|