From fd7d2b8e791e2404f5b90704df250c230656ae2e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 6 Jul 2026 02:31:32 -0400 Subject: [PATCH] Emit identifiable error frames on the direct-write path MJ-16: The compressed direct-write path emitted generic {0xFF, 0xFF} error frames, so a failing command was unidentifiable. The published spec says error frames are 0xFF followed by the command code ({0xFF, cmd}). Make the firmware conform by setting the second byte to the failing command's low byte, matching the existing {0xFF, 0x72} gray4 END frame. Sites (src/display_service.cpp): - handleDirectWriteCompressedData length-overflow guard -> {0xFF, 0x71} (DATA) - handleDirectWriteCompressedData zlib-stream failure -> {0xFF, 0x71} (DATA) - handleDirectWriteStart decompressed-size mismatch -> {0xFF, 0x70} (START) - handleDirectWriteStart initial zlib-stream failure -> {0xFF, 0x70} (START) - handlePartialWriteStart zero logical-size guard -> {0xFF, 0x76} (PARTIAL START) - handleDirectWriteEnd compressed final-flush failure -> {0xFF, 0x72} (END) Backward-compatible with updated clients: py-opendisplay PR #120's is_compressed_failure_frame() accepts both {0xFF, 0xFF} and {0xFF, 0x70} for the compressed-START fallback, and the website direct-write handler (PR #28) treats any leading-0xFF frame as an error. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_012g2e8mr132vcizx92WsgiR --- src/display_service.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/display_service.cpp b/src/display_service.cpp index e508d44..2fe7d0a 100644 --- a/src/display_service.cpp +++ b/src/display_service.cpp @@ -1366,13 +1366,13 @@ void updatemsdata(){ void handleDirectWriteCompressedData(uint8_t* data, uint16_t len) { if (len > UINT32_MAX - directWriteCompressedReceived) { cleanupDirectWriteState(true); - uint8_t errorResponse[] = {0xFF, 0xFF}; + uint8_t errorResponse[] = {0xFF, 0x71}; sendResponse(errorResponse, sizeof(errorResponse)); return; } if (!zlib_stream_to_direct_write(data, len, false)) { cleanupDirectWriteState(true); - uint8_t errorResponse[] = {0xFF, 0xFF}; + uint8_t errorResponse[] = {0xFF, 0x71}; sendResponse(errorResponse, sizeof(errorResponse)); return; } @@ -1487,7 +1487,7 @@ if (partialCtx.active) cleanup_partial_write_state(); memcpy(&directWriteDecompressedTotal, data, 4); if (directWriteDecompressedTotal != directWriteTotalBytes) { cleanupDirectWriteState(false); - uint8_t errorResponse[] = {0xFF, 0xFF}; + uint8_t errorResponse[] = {0xFF, 0x70}; sendResponse(errorResponse, sizeof(errorResponse)); return; } @@ -1518,7 +1518,7 @@ if (partialCtx.active) cleanup_partial_write_state(); uint32_t compressedDataLen = len - 4; if (!zlib_stream_to_direct_write(data + 4, compressedDataLen, false)) { cleanupDirectWriteState(false); - uint8_t errorResponse[] = {0xFF, 0xFF}; + uint8_t errorResponse[] = {0xFF, 0x70}; sendResponse(errorResponse, sizeof(errorResponse)); return; } @@ -1582,7 +1582,7 @@ void handlePartialWriteStart(uint8_t* data, uint16_t len) { uint32_t expectedLogicalSize = planeBytes * 2u; if (expectedLogicalSize == 0) { - uint8_t errResponse[] = {0xFF, 0xFF}; + uint8_t errResponse[] = {0xFF, 0x76}; sendResponse(errResponse, sizeof(errResponse)); return; } @@ -1694,7 +1694,7 @@ void handleDirectWriteEnd(uint8_t* data, uint16_t len) { directWriteStartTime = 0; if (directWriteCompressed && !zlib_stream_to_direct_write(nullptr, 0, true)) { cleanupDirectWriteState(true); - uint8_t errorResponse[] = {0xFF, 0xFF}; + uint8_t errorResponse[] = {0xFF, 0x72}; sendResponse(errorResponse, sizeof(errorResponse)); return; }