mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-07-31 01:08:14 +00:00
feat(screenshot): extend e-ink screenshot support via GxEPD2 patch
- Add lib/GxEPD2-patch/src/GxEPD2_BW.h: local patched copy of GxEPD2_BW.h
that exposes getBuffer()/getBufferSize() under ENABLE_SCREENSHOT guard.
Include guard (_GxEPD2_BW_H_) prevents double-inclusion of the installed
library version.
- GxEPDDisplay.h: use patched header via relative include when
ENABLE_SCREENSHOT so the patch takes precedence over the installed lib
(PlatformIO adds library paths before -I build_flags).
- DisplayDriver.h: add virtual getBuffer()/getBufferSize()/getDisplayType()
defaults (nullptr/0/0) under ENABLE_SCREENSHOT.
- SH1106Display.h / SSD1306Display.h / GxEPDDisplay.h: add concrete overrides;
getDisplayType() returns 0 (OLED) or 1 (e-ink).
- MyMesh.cpp/h: replace fragile C-cast with virtual dispatch in
handleScreenshotRequest(); extend 5-byte header to 6 bytes by appending
display_type so the host tool can decode the correct pixel layout.
- tools/screenshot.py: parse 6-byte header; add eink_buffer_to_image()
that decodes the row-major MSB-first GxEPD2 buffer with DISPLAY_ROTATION=1
(phys_x = 127-ly, phys_y = lx); dispatch on display_type.
- variants/wio-tracker-l1-eink/platformio.ini: add
[env:WioTrackerL1Eink_companion_dual_dev] with ENABLE_SCREENSHOT.
- variants/wio-tracker-l1/platformio.ini: unchanged (OLED env already exists).
Builds verified: WioTrackerL1Eink_companion_dual_dev SUCCESS,
WioTrackerL1Eink_companion_radio_ble SUCCESS (unaffected).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2077,35 +2077,19 @@ void MyMesh::handleScreenshotRequest() {
|
||||
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
DisplayDriver* display = ui_task->getDisplay();
|
||||
if (!display) {
|
||||
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t* buffer = nullptr;
|
||||
int bufferSize = 0;
|
||||
|
||||
// Try SH1106Display first (used by Wio L1)
|
||||
// Use C-style cast since RTTI is disabled (-fno-rtti)
|
||||
SH1106Display* sh1106 = (SH1106Display*)display;
|
||||
if (sh1106) {
|
||||
buffer = sh1106->getBuffer();
|
||||
bufferSize = (display->width() * display->height()) / 8;
|
||||
} else {
|
||||
// Fallback: try SSD1306Display
|
||||
SSD1306Display* ssd1306 = (SSD1306Display*)display;
|
||||
if (ssd1306) {
|
||||
buffer = ssd1306->getBuffer();
|
||||
bufferSize = (display->width() * display->height()) / 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const uint8_t* buffer = display->getBuffer();
|
||||
uint16_t bufferSize = display->getBufferSize();
|
||||
|
||||
if (buffer && bufferSize > 0) {
|
||||
sendScreenshotResponse(display, buffer, bufferSize);
|
||||
} else {
|
||||
// No supported display type
|
||||
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
|
||||
}
|
||||
#else
|
||||
@@ -2113,26 +2097,26 @@ void MyMesh::handleScreenshotRequest() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void MyMesh::sendScreenshotResponse(DisplayDriver* display, uint8_t* buffer, int bufferSize) {
|
||||
// MAX_FRAME_SIZE is 172 bytes, but we need to send 1026 bytes (3 header + 1024 buffer)
|
||||
// We need to split into multiple frames
|
||||
// Frame format: RESP_CODE_SCREENSHOT, width, height, chunk_index, total_chunks, [chunk_data...]
|
||||
|
||||
const int MAX_DATA_PER_FRAME = MAX_FRAME_SIZE - 5; // 5 bytes header
|
||||
void MyMesh::sendScreenshotResponse(DisplayDriver* display, const uint8_t* buffer, uint16_t bufferSize) {
|
||||
// Frame format: RESP_CODE_SCREENSHOT, width, height, chunk_idx, total_chunks, display_type, [data]
|
||||
// display_type: 0=OLED (page-based), 1=e-ink (row-major, MSB-first, 1=white/0=black)
|
||||
const int HEADER_SIZE = 6;
|
||||
const int MAX_DATA_PER_FRAME = MAX_FRAME_SIZE - HEADER_SIZE;
|
||||
int totalChunks = (bufferSize + MAX_DATA_PER_FRAME - 1) / MAX_DATA_PER_FRAME;
|
||||
|
||||
|
||||
for (int chunkIdx = 0; chunkIdx < totalChunks; chunkIdx++) {
|
||||
int i = 0;
|
||||
out_frame[i++] = RESP_CODE_SCREENSHOT;
|
||||
out_frame[i++] = display->width();
|
||||
out_frame[i++] = display->height();
|
||||
out_frame[i++] = chunkIdx;
|
||||
out_frame[i++] = totalChunks;
|
||||
|
||||
int chunkSize = min(MAX_DATA_PER_FRAME, bufferSize - chunkIdx * MAX_DATA_PER_FRAME);
|
||||
out_frame[i++] = (uint8_t)display->width();
|
||||
out_frame[i++] = (uint8_t)display->height();
|
||||
out_frame[i++] = (uint8_t)chunkIdx;
|
||||
out_frame[i++] = (uint8_t)totalChunks;
|
||||
out_frame[i++] = display->getDisplayType();
|
||||
|
||||
int chunkSize = min(MAX_DATA_PER_FRAME, (int)bufferSize - chunkIdx * MAX_DATA_PER_FRAME);
|
||||
memcpy(&out_frame[i], buffer + chunkIdx * MAX_DATA_PER_FRAME, chunkSize);
|
||||
i += chunkSize;
|
||||
|
||||
|
||||
_serial->writeFrame(out_frame, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ private:
|
||||
bool isValidClientRepeatFreq(uint32_t f) const;
|
||||
#ifdef ENABLE_SCREENSHOT
|
||||
void handleScreenshotRequest();
|
||||
void sendScreenshotResponse(DisplayDriver* display, uint8_t* buffer, int bufferSize);
|
||||
void sendScreenshotResponse(DisplayDriver* display, const uint8_t* buffer, uint16_t bufferSize);
|
||||
#endif
|
||||
|
||||
UITask* getUITask() { return (UITask*)_ui; }
|
||||
|
||||
Reference in New Issue
Block a user