Skip to content

Commit 5bc8e50

Browse files
committed
feature: implement drawrect
1 parent ae08c84 commit 5bc8e50

2 files changed

Lines changed: 158 additions & 5 deletions

File tree

src/matrix_panel_fpga.cpp

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,119 @@ void MatrixPanel_FPGA_SPI::drawFrameRGB888(const uint8_t *data, size_t length) {
310310
do_drawFrameRGB888_(data, length);
311311
}
312312

313+
void MatrixPanel_FPGA_SPI::do_drawRectRGB888_(int16_t x, int16_t y, int16_t w,
314+
int16_t h, const uint8_t *data,
315+
size_t length) {
316+
if (!initialized) {
317+
ESP_LOGI("drawRectRGB888()",
318+
"Tried to set output brightness before begin()");
319+
return;
320+
}
321+
if (data == nullptr) {
322+
ESP_LOGE("MatrixPanel_FPGA_SPI:drawRectRGB888",
323+
"Invalid data passed to drawRectRGB888 nullptr! (length=%d)",
324+
length);
325+
return;
326+
}
327+
if (x < 0 || y < 0 || w <= 0 || h <= 0) {
328+
ESP_LOGE("MatrixPanel_FPGA_SPI:drawRectRGB888",
329+
"Invalid rect params x=%d y=%d w=%d h=%d", x, y, w, h);
330+
return;
331+
}
332+
const size_t expected_len = static_cast<size_t>(w) *
333+
static_cast<size_t>(h) * 3;
334+
if (length != expected_len) {
335+
ESP_LOGE("MatrixPanel_FPGA_SPI:drawRectRGB888",
336+
"Invalid data length=%d expected=%d", length, expected_len);
337+
return;
338+
}
339+
SpiLockGuard spi_lock(this);
340+
if (!spi_lock.locked())
341+
return;
342+
if (!wait_for_fpga_resetstatus_())
343+
return;
344+
345+
uint8_t header[7];
346+
uint8_t header_len = 0;
347+
header[header_len++] = 'X'; // Command byte
348+
if (PIXELS_PER_ROW <= 0xff) {
349+
header[header_len++] = static_cast<uint8_t>(x);
350+
} else {
351+
header[header_len++] = static_cast<uint8_t>((x >> 8) & 0xFF);
352+
header[header_len++] = static_cast<uint8_t>(x & 0xFF);
353+
}
354+
header[header_len++] = static_cast<uint8_t>(y);
355+
if (PIXELS_PER_ROW <= 0xff) {
356+
header[header_len++] = static_cast<uint8_t>(w);
357+
} else {
358+
header[header_len++] = static_cast<uint8_t>((w >> 8) & 0xFF);
359+
header[header_len++] = static_cast<uint8_t>(w & 0xFF);
360+
}
361+
header[header_len++] = static_cast<uint8_t>(h);
362+
363+
spi_transaction_t t = {
364+
.length = (size_t)(8 * header_len), // bits
365+
.tx_buffer = header,
366+
};
367+
esp_err_t err = spi_device_transmit(spi_bus, &t);
368+
if (err != ESP_OK) {
369+
ESP_LOGE("MatrixPanel_FPGA_SPI:drawRectRGB888",
370+
"SPI transmit failed: %s", esp_err_to_name(err));
371+
return;
372+
}
373+
374+
const size_t chunk_bytes =
375+
std::min(static_cast<size_t>(SPI_MAX_DMA_LEN), length);
376+
uint8_t *buf =
377+
static_cast<uint8_t *>(heap_caps_malloc(chunk_bytes, MALLOC_CAP_DMA));
378+
if (buf == nullptr) {
379+
ESP_LOGE("MatrixPanel_FPGA_SPI:drawRectRGB888",
380+
"DMA alloc failed for rect chunk (%u bytes)",
381+
static_cast<unsigned>(chunk_bytes));
382+
return;
383+
}
384+
385+
size_t offset = 0;
386+
while (offset < length) {
387+
const size_t chunk = std::min(length - offset, chunk_bytes);
388+
memcpy(buf, data + offset, chunk);
389+
spi_transaction_t t2 = {
390+
.length = static_cast<size_t>(chunk * 8), // bits
391+
.tx_buffer = buf,
392+
};
393+
esp_err_t err2 = spi_device_transmit(spi_bus, &t2);
394+
if (err2 != ESP_OK) {
395+
ESP_LOGE("MatrixPanel_FPGA_SPI:drawRectRGB888",
396+
"SPI transmit failed: %s", esp_err_to_name(err2));
397+
break;
398+
}
399+
offset += chunk;
400+
}
401+
402+
heap_caps_free(buf);
403+
wait_for_fpga_busy_clear_();
404+
}
405+
406+
void MatrixPanel_FPGA_SPI::drawRectRGB888(int16_t x, int16_t y, int16_t w,
407+
int16_t h, const uint8_t *data,
408+
size_t length) {
409+
if (use_worker_) {
410+
if (!tx_q_ || !tx_task_)
411+
return;
412+
Job j;
413+
j.op = Op::DRAW_RECT;
414+
j.x = x;
415+
j.y = static_cast<uint8_t>(y);
416+
j.w = w;
417+
j.h = h;
418+
j.data = data;
419+
j.length = length;
420+
(void)xQueueSend(tx_q_, &j, 0);
421+
return;
422+
}
423+
do_drawRectRGB888_(x, y, w, h, data, length);
424+
}
425+
313426
void MatrixPanel_FPGA_SPI::do_drawRowRGB888_(const uint8_t y,
314427
const uint8_t *data,
315428
size_t length) {
@@ -730,6 +843,11 @@ void MatrixPanel_FPGA_SPI::run_test_graphic(uint32_t delay_ms) {
730843
// - blue center band via fillRect
731844
// - yellow left column, magenta right column for edge accents
732845
// - opposing diagonals (orange/white) to cover drawPixelRGB888
846+
// - centered drawRectRGB888 rect: size=max(4, width/5)xmax(4, height/3)
847+
// BLACK GRADIANT RED
848+
// .............GRADIANT..............
849+
// .............GRADIANT..............
850+
// TEAL/GREEN GRADIANT YELLOW
733851
// - brightness pushed to 255 and the frame swapped to display the pattern
734852
clearScreen();
735853
delay_if_needed();
@@ -781,6 +899,34 @@ void MatrixPanel_FPGA_SPI::run_test_graphic(uint32_t delay_ms) {
781899
wait_for_worker_idle();
782900
delay_if_needed();
783901

902+
// Buffered rectangle: gradient checker to exercise drawRectRGB888.
903+
const int rect_w = std::max(4, width / 5);
904+
const int rect_h = std::max(4, height / 3);
905+
const int rect_x = std::max(0, (width - rect_w) / 2);
906+
const int rect_y = std::max(0, (height - rect_h) / 2);
907+
const int rect_w_denom = std::max(1, rect_w - 1);
908+
const int rect_h_denom = std::max(1, rect_h - 1);
909+
std::vector<uint8_t> rect_buf(
910+
static_cast<size_t>(rect_w) * static_cast<size_t>(rect_h) * 3);
911+
for (int y = 0; y < rect_h; ++y) {
912+
for (int x = 0; x < rect_w; ++x) {
913+
const size_t idx =
914+
(static_cast<size_t>(y) * rect_w + x) * 3;
915+
const uint8_t r = static_cast<uint8_t>(
916+
(x * 255) / rect_w_denom);
917+
const uint8_t g = static_cast<uint8_t>(
918+
(y * 255) / rect_h_denom);
919+
const uint8_t b = ((x + y) & 1) ? 0x20 : 0xA0;
920+
rect_buf[idx] = r;
921+
rect_buf[idx + 1] = g;
922+
rect_buf[idx + 2] = b;
923+
}
924+
}
925+
drawRectRGB888(rect_x, rect_y, rect_w, rect_h, rect_buf.data(),
926+
rect_buf.size());
927+
wait_for_worker_idle();
928+
delay_if_needed();
929+
784930
// Diagonals: orange from top-left and white from top-right.
785931
const int diag_length = std::min(width, height);
786932
const int diag_step = std::max(1, diag_length / 16);

src/matrix_panel_fpga.hpp

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ class MatrixPanel_FPGA_SPI {
7474
bool queue_has_space(size_t slots = 1) const;
7575
bool worker_is_idle() const;
7676
bool is_worker_enabled() const { return use_worker_; }
77+
void drawRectRGB888(int16_t x, int16_t y, int16_t w, int16_t h,
78+
const uint8_t *data, size_t length);
7779
void run_test_graphic(uint32_t delay_ms = 10);
7880
void swapFrame();
7981
void fulfillWatchdog();
@@ -139,6 +141,8 @@ class MatrixPanel_FPGA_SPI {
139141
uint8_t b);
140142
void do_drawRowRGB888_(const uint8_t y, const uint8_t *data, size_t length);
141143
void do_drawFrameRGB888_(const uint8_t *data, size_t length);
144+
void do_drawRectRGB888_(int16_t x, int16_t y, int16_t w, int16_t h,
145+
const uint8_t *data, size_t length);
142146
void do_swapFrame_();
143147
void do_fulfillWatchdog_();
144148
void do_setBrightness8_(const uint8_t b);
@@ -179,19 +183,20 @@ class MatrixPanel_FPGA_SPI {
179183
SET_BRIGHTNESS,
180184
CLEAR,
181185
DRAW_FRAME,
186+
DRAW_RECT,
182187
COPY_FRAME,
183188
DRAW_PIXEL,
184189
FILL_RECT
185190
};
186191
struct Job {
187192
Op op;
188-
const uint8_t *data = nullptr; // for DRAW_ROW / DRAW_FRAME
189-
size_t length = 0; // for DRAW_ROW / DRAW_FRAME
193+
const uint8_t *data = nullptr; // for DRAW_ROW / DRAW_FRAME / DRAW_RECT
194+
size_t length = 0; // for DRAW_ROW / DRAW_FRAME / DRAW_RECT
190195

191196
uint8_t y = 0; // row index
192-
int16_t x = 0; // for DRAW_PIXEL / FILL_RECT
193-
int16_t w = 0; // for FILL_RECT
194-
int16_t h = 0; // for FILL_RECT
197+
int16_t x = 0; // for DRAW_PIXEL / DRAW_RECT / FILL_RECT
198+
int16_t w = 0; // for DRAW_RECT / FILL_RECT
199+
int16_t h = 0; // for DRAW_RECT / FILL_RECT
195200

196201
uint8_t r = 0, g = 0,
197202
b = 0; // for colors (FILL_SCREEN / DRAW_PIXEL / FILL_RECT)
@@ -227,6 +232,8 @@ class MatrixPanel_FPGA_SPI {
227232
do_copyFrame_();
228233
else if (j.op == Op::DRAW_FRAME)
229234
do_drawFrameRGB888_(j.data, j.length);
235+
else if (j.op == Op::DRAW_RECT)
236+
do_drawRectRGB888_(j.x, j.y, j.w, j.h, j.data, j.length);
230237
else if (j.op == Op::DRAW_PIXEL)
231238
do_drawPixelRGB888_(j.x, j.y, j.r, j.g, j.b);
232239
else if (j.op == Op::FILL_RECT)

0 commit comments

Comments
 (0)