@@ -893,13 +893,24 @@ void initDisplay(){
893893 writeSerial (String (" Width: " ) + String (epd.width ()));
894894 epd.allocBuffer ();
895895 if (globalConfig.displays [0 ].color_scheme == 1 )epd.allocBuffer (true );
896- epd.fillScreen (BBEP_WHITE);
897- epd.setTextColor (BBEP_BLACK, BBEP_WHITE);
896+ // For 4 grayscale mode, use GRAY3 (white) and GRAY0 (black)
897+ if (globalConfig.displays [0 ].color_scheme == 5 ){
898+ epd.fillScreen (BBEP_GRAY3);
899+ epd.setTextColor (BBEP_GRAY0, BBEP_GRAY3);
900+ } else {
901+ epd.fillScreen (BBEP_WHITE);
902+ epd.setTextColor (BBEP_BLACK, BBEP_WHITE);
903+ }
898904 String chipId = getChipIdHex ();
899905 writeSerial (" Chip ID for display: " + chipId);
900906 if (epd.width () > 500 ){
901907 epd.setFont (FONT_12x16);
902- epd.drawSprite (epd_bitmap_logo, 152 , 152 , 19 , 600 , 22 , BBEP_BLACK);
908+ // Use appropriate color constants based on color scheme
909+ if (globalConfig.displays [0 ].color_scheme == 5 ){
910+ epd.drawSprite (epd_bitmap_logo, 152 , 152 , 19 , 600 , 22 , BBEP_GRAY0);
911+ } else {
912+ epd.drawSprite (epd_bitmap_logo, 152 , 152 , 19 , 600 , 22 , BBEP_BLACK);
913+ }
903914 epd.setCursor (100 , 100 );
904915 epd.print (" openepaperlink.org" );
905916 epd.setCursor (100 , 200 );
@@ -915,6 +926,13 @@ void initDisplay(){
915926 epd.fillRect (140 ,320 ,10 ,10 ,BBEP_BLACK);
916927 epd.fillRect (150 ,320 ,10 ,10 ,BBEP_WHITE);
917928 }
929+ if (globalConfig.displays [0 ].color_scheme == 5 ){
930+ writeSerial (" 4 grayscale test" );
931+ epd.fillRect (100 ,320 ,10 ,10 ,BBEP_GRAY0);
932+ epd.fillRect (110 ,320 ,10 ,10 ,BBEP_GRAY1);
933+ epd.fillRect (120 ,320 ,10 ,10 ,BBEP_GRAY2);
934+ epd.fillRect (130 ,320 ,10 ,10 ,BBEP_GRAY3);
935+ }
918936 }
919937 else {
920938 epd.setFont (FONT_6x8);
@@ -1107,12 +1125,25 @@ void handleImageInfo(uint8_t* data, uint16_t len) {
11071125 writeSerial (" Next check in: " + String (nextCheckIn));
11081126 writeSerial (" Setting up image data buffer..." );
11091127 cleanupImageMemory ();
1110- if (dataSize > MAX_IMAGE_SIZE) {
1111- writeSerial (" ERROR: Image too large (" + String (dataSize) + " bytes, max: " + String (MAX_IMAGE_SIZE) + " bytes)" );
1128+ bool isCompressed = (dataType == 0x30 );
1129+ uint32_t maxSize = isCompressed ? MAX_COMPRESSED_SIZE : MAX_IMAGE_SIZE;
1130+ if (dataSize > maxSize) {
1131+ writeSerial (" ERROR: Image too large (" + String (dataSize) + " bytes, max: " + String (maxSize) + " bytes)" );
11121132 return ;
11131133 }
1114- currentImage.data = imageDataBuffer;
1115- writeSerial (" Using global image buffer: " + String (dataSize) + " bytes" );
1134+ // For compressed images larger than static buffer, allocate dynamically
1135+ // For uncompressed or small compressed images, use static buffer
1136+ if (isCompressed && dataSize > MAX_IMAGE_SIZE) {
1137+ currentImage.data = (uint8_t *)malloc (dataSize);
1138+ if (currentImage.data == nullptr ) {
1139+ writeSerial (" ERROR: Failed to allocate " + String (dataSize) + " bytes for compressed image" );
1140+ return ;
1141+ }
1142+ writeSerial (" Allocated dynamic buffer: " + String (dataSize) + " bytes" );
1143+ } else {
1144+ currentImage.data = imageDataBuffer;
1145+ writeSerial (" Using static image buffer: " + String (dataSize) + " bytes" );
1146+ }
11161147 currentImage.size = dataSize;
11171148 currentImage.received = 0 ;
11181149 currentImage.dataType = dataType;
@@ -1395,6 +1426,86 @@ void drawImageData() {
13951426 }
13961427 }
13971428 }
1429+ else if (currentImage.dataType == 0x22 ) {
1430+ writeSerial (" 6-color image detected, drawing with full color support..." );
1431+ uint32_t pixelIndex = 0 ;
1432+ uint32_t planeSize = currentImage.size / 3 ; // Each plane is 1/3 of total size
1433+ uint32_t redPlaneOffset = planeSize; // Second plane (R/Y)
1434+ uint32_t greenPlaneOffset = planeSize * 2 ; // Third plane (G/B)
1435+
1436+ for (uint16_t y = 0 ; y < displayWidth; y++) {
1437+ for (uint16_t x = 0 ; x < displayHeight; x++) {
1438+ if (pixelIndex >= planeSize) break ;
1439+ uint8_t pixelByte = ~currentImage.data [pixelIndex]; // First plane (B/W) is inverted
1440+ uint8_t redByte = currentImage.data [pixelIndex + redPlaneOffset]; // Second plane (R/Y)
1441+ uint8_t greenByte = currentImage.data [pixelIndex + greenPlaneOffset]; // Third plane (G/B)
1442+
1443+ for (int bit = 7 ; bit >= 0 ; bit--) {
1444+ if (x >= displayHeight) break ;
1445+
1446+ bool plane1 = (pixelByte >> bit) & 0x01 ; // B/W base
1447+ bool plane2 = (redByte >> bit) & 0x01 ; // R/Y
1448+ bool plane3 = (greenByte >> bit) & 0x01 ; // G/B
1449+
1450+ // Decode 6 colors: BLACK=000, WHITE=100, RED=110, YELLOW=010, GREEN=101, BLUE=001
1451+ if (!plane1 && !plane2 && !plane3) {
1452+ epd.drawPixel (displayWidth - y, x, BBEP_BLACK);
1453+ } else if (plane1 && !plane2 && !plane3) {
1454+ epd.drawPixel (displayWidth - y, x, BBEP_WHITE);
1455+ } else if (plane1 && plane2 && !plane3) {
1456+ epd.drawPixel (displayWidth - y, x, BBEP_RED);
1457+ } else if (!plane1 && plane2 && !plane3) {
1458+ epd.drawPixel (displayWidth - y, x, BBEP_YELLOW);
1459+ } else if (plane1 && !plane2 && plane3) {
1460+ epd.drawPixel (displayWidth - y, x, BBEP_GREEN);
1461+ } else if (!plane1 && !plane2 && plane3) {
1462+ epd.drawPixel (displayWidth - y, x, BBEP_BLUE);
1463+ } else {
1464+ // Fallback for unused combinations (111, 011)
1465+ epd.drawPixel (displayWidth - y, x, BBEP_BLACK);
1466+ }
1467+ x++;
1468+ }
1469+ x--;
1470+ pixelIndex++;
1471+ }
1472+ }
1473+ }
1474+ else if (currentImage.dataType == 0x23 ) {
1475+ writeSerial (" 4-grayscale image detected, drawing with grayscale support..." );
1476+ uint32_t pixelIndex = 0 ;
1477+ uint16_t imgWidth = currentImage.width ;
1478+ uint16_t imgHeight = currentImage.height ;
1479+ uint16_t bytesPerRow = (imgWidth + 3 ) / 4 ; // Round up to handle width not divisible by 4
1480+
1481+ for (uint16_t y = 0 ; y < displayWidth && y < imgHeight; y++) {
1482+ for (uint16_t byteInRow = 0 ; byteInRow < bytesPerRow; byteInRow++) {
1483+ if (pixelIndex >= currentImage.size ) break ;
1484+ uint8_t pixelByte = currentImage.data [pixelIndex];
1485+ uint16_t xStart = byteInRow * 4 ;
1486+
1487+ // 4 grayscale: 2 bits per pixel, 4 pixels per byte
1488+ // Encoding: 00=Black (GRAY0), 01=DarkGray (GRAY1), 10=LightGray (GRAY2), 11=White (GRAY3)
1489+ for (int pixel = 0 ; pixel < 4 ; pixel++) {
1490+ uint16_t x = xStart + pixel;
1491+ if (x >= displayHeight || x >= imgWidth) break ;
1492+
1493+ uint8_t grayLevel = (pixelByte >> (6 - pixel * 2 )) & 0x03 ;
1494+ // Map grayscale levels using constants: GRAY0=black, GRAY1=dark gray, GRAY2=light gray, GRAY3=white
1495+ if (grayLevel == 0 ) {
1496+ epd.drawPixel (displayWidth - y, x, BBEP_GRAY0);
1497+ } else if (grayLevel == 1 ) {
1498+ epd.drawPixel (displayWidth - y, x, BBEP_GRAY1);
1499+ } else if (grayLevel == 2 ) {
1500+ epd.drawPixel (displayWidth - y, x, BBEP_GRAY2);
1501+ } else {
1502+ epd.drawPixel (displayWidth - y, x, BBEP_GRAY3);
1503+ }
1504+ }
1505+ pixelIndex++;
1506+ }
1507+ }
1508+ }
13981509 else if (currentImage.dataType == 0x30 ) {
13991510 writeSerial (" Compressed image detected, decompressing with chunked approach..." );
14001511 if (!decompressImageDataChunked ()) {
@@ -1404,7 +1515,7 @@ void drawImageData() {
14041515 writeSerial (" Chunked decompression and drawing complete." );
14051516 }
14061517 else {
1407- writeSerial (" ERROR: Unsupported image type. " );
1518+ writeSerial (" ERROR: Unsupported image type: 0x " + String (currentImage. dataType , HEX) );
14081519 }
14091520 writeSerial (" Image drawing complete." );
14101521}
@@ -1462,11 +1573,9 @@ void handleDisplayInfo(){
14621573 for (int i = 0 ; i < 4 ; i++) {
14631574 response[offset++] = 0x00 ;
14641575 }
1465- // Offset 30: Color count (1=BW, 2=BWR/BWY, 3=BWRY)
1466- // Our display is monochrome (black/white only)
1467- if (globalConfig.displays [0 ].color_scheme == 0 )response[offset++] = 0x01 ; // Monochrome
1468- else if (globalConfig.displays [0 ].color_scheme == 1 )response[offset++] = 0x02 ;
1469- else response[offset++] = 0x00 ;
1576+ // Offset 30: Color scheme (0=bw, 1=bwr, 2=bwy, 3=bwry, 4=bwgbry, 5=bw4)
1577+ // Send actual color_scheme value
1578+ response[offset++] = globalConfig.displays [0 ].color_scheme & 0xFF ;
14701579
14711580 writeSerial (" Display Info - Width: " + String (width) + " , Height: " + String (height) + " , Colors: " + String (globalConfig.displays [0 ].color_scheme ));
14721581 // Send the response
@@ -1496,9 +1605,8 @@ void buildDynamicConfigResponse(uint8_t* buffer, uint16_t* len) {
14961605 buffer[offset++] = 0x00 ;
14971606 buffer[offset++] = 0x00 ;
14981607 buffer[offset++] = 0x00 ;
1499- if (globalConfig.displays [0 ].color_scheme == 0 )buffer[offset++] = 0x01 ; // Monochrome
1500- else if (globalConfig.displays [0 ].color_scheme == 1 )buffer[offset++] = 0x02 ;
1501- else buffer[offset++] = 0x00 ;
1608+ // Send actual color_scheme value (0-5) instead of simplified color count
1609+ buffer[offset++] = globalConfig.displays [0 ].color_scheme & 0xFF ;
15021610 buffer[offset++] = 0x00 ;
15031611 buffer[offset++] = 0x00 ;
15041612 buffer[offset++] = 0x00 ;
@@ -1619,6 +1727,11 @@ void buildDynamicConfigResponse(uint8_t* buffer, uint16_t* len) {
16191727
16201728void cleanupImageMemory () {
16211729 writeSerial (" === CLEANING UP IMAGE MEMORY ===" );
1730+ // Free dynamically allocated buffer if it exists
1731+ if (currentImage.data != nullptr && currentImage.data != imageDataBuffer) {
1732+ free (currentImage.data );
1733+ writeSerial (" Freed dynamically allocated image buffer" );
1734+ }
16221735 memset (imageDataBuffer, 0 , MAX_IMAGE_SIZE);
16231736 memset (blocksReceived, 0 , MAX_BLOCKS * sizeof (bool ));
16241737 memset (blockBytesReceived, 0 , MAX_BLOCKS * sizeof (uint32_t ));
@@ -1683,6 +1796,10 @@ bool decompressImageDataChunked(){
16831796 // Buffer for colored image first plane
16841797 uint8_t * firstPlaneBuffer = nullptr ;
16851798 uint32_t firstPlaneSize = 0 ;
1799+ // Buffers for 6-color image (planes 2 and 3)
1800+ uint8_t * secondPlaneBuffer = nullptr ;
1801+ uint8_t * thirdPlaneBuffer = nullptr ;
1802+ uint32_t secondPlaneSize = 0 ;
16861803 writeSerial (" Starting chunked decompression and direct drawing..." );
16871804 int res;
16881805 do {
@@ -1712,7 +1829,7 @@ bool decompressImageDataChunked(){
17121829 writeSerial (" Drawing bounds: " + String (drawWidth) + " x" + String (drawHeight));
17131830
17141831 // Allocate buffer for colored image first plane
1715- if (colorType == 2 ) {
1832+ if (colorType == 2 || colorType == 3 ) {
17161833 firstPlaneSize = (imgWidth * imgHeight) / 8 ;
17171834 firstPlaneBuffer = (uint8_t *)malloc (firstPlaneSize);
17181835 if (!firstPlaneBuffer) {
@@ -1721,6 +1838,19 @@ bool decompressImageDataChunked(){
17211838 }
17221839 writeSerial (" Allocated first plane buffer: " + String (firstPlaneSize) + " bytes" );
17231840 }
1841+ if (colorType == 3 ) {
1842+ // For 6-color, we also need buffers for planes 2 and 3
1843+ secondPlaneSize = firstPlaneSize;
1844+ secondPlaneBuffer = (uint8_t *)malloc (secondPlaneSize);
1845+ thirdPlaneBuffer = (uint8_t *)malloc (secondPlaneSize);
1846+ if (!secondPlaneBuffer || !thirdPlaneBuffer) {
1847+ writeSerial (" ERROR: Failed to allocate 6-color plane buffers" );
1848+ if (secondPlaneBuffer) free (secondPlaneBuffer);
1849+ if (thirdPlaneBuffer) free (thirdPlaneBuffer);
1850+ return false ;
1851+ }
1852+ writeSerial (" Allocated 6-color plane buffers: " + String (secondPlaneSize) + " bytes each" );
1853+ }
17241854 }
17251855 } else {
17261856 uint32_t pixelByteIndex = pixelBytesProcessed;
@@ -1735,6 +1865,31 @@ bool decompressImageDataChunked(){
17351865 epd.drawPixel (displayWidth - y, x + (7 -bit), pixelValue ? BBEP_BLACK : BBEP_WHITE);
17361866 }
17371867 }
1868+ } else if (colorType == 4 ) {
1869+ // 4-grayscale image: 2 bits per pixel, 4 pixels per byte
1870+ // Encoding: 00=Black (GRAY0), 01=DarkGray (GRAY1), 10=LightGray (GRAY2), 11=White (GRAY3)
1871+ // Calculate position: bytes per row = imgWidth / 4 (4 pixels per byte)
1872+ uint16_t bytesPerRow = (imgWidth + 3 ) / 4 ; // Round up
1873+ uint16_t y = pixelByteIndex / bytesPerRow;
1874+ uint16_t byteInRow = pixelByteIndex % bytesPerRow;
1875+ uint16_t xStart = byteInRow * 4 ;
1876+
1877+ for (int pixel = 0 ; pixel < 4 ; pixel++) {
1878+ uint16_t x = xStart + pixel;
1879+ if (y < ((imgHeight < displayWidth) ? imgHeight : displayWidth) && x < ((imgWidth < displayHeight) ? imgWidth : displayHeight)) {
1880+ uint8_t grayLevel = (byte >> (6 - pixel * 2 )) & 0x03 ;
1881+ // Map grayscale levels using constants: GRAY0=black, GRAY1=dark gray, GRAY2=light gray, GRAY3=white
1882+ if (grayLevel == 0 ) {
1883+ epd.drawPixel (displayWidth - y, x, BBEP_GRAY0);
1884+ } else if (grayLevel == 1 ) {
1885+ epd.drawPixel (displayWidth - y, x, BBEP_GRAY1);
1886+ } else if (grayLevel == 2 ) {
1887+ epd.drawPixel (displayWidth - y, x, BBEP_GRAY2);
1888+ } else {
1889+ epd.drawPixel (displayWidth - y, x, BBEP_GRAY3);
1890+ }
1891+ }
1892+ }
17381893 } else if (colorType == 2 ) {
17391894 // Colored image - dual plane encoding
17401895 uint32_t redPlaneOffset = firstPlaneSize;
@@ -1770,6 +1925,60 @@ bool decompressImageDataChunked(){
17701925 }
17711926 }
17721927 }
1928+ } else if (colorType == 3 ) {
1929+ // 6-color image - triple plane encoding
1930+ uint32_t planeSize = firstPlaneSize;
1931+ uint32_t redPlaneOffset = planeSize;
1932+ uint32_t greenPlaneOffset = planeSize * 2 ;
1933+
1934+ if (pixelByteIndex < redPlaneOffset) {
1935+ // First plane (inverted B/W data) - store in buffer
1936+ if (pixelByteIndex < firstPlaneSize) {
1937+ firstPlaneBuffer[pixelByteIndex] = byte;
1938+ }
1939+ } else if (pixelByteIndex < greenPlaneOffset) {
1940+ // Second plane (R/Y data) - store in buffer
1941+ uint32_t secondPlaneIndex = pixelByteIndex - redPlaneOffset;
1942+ if (secondPlaneIndex < secondPlaneSize) {
1943+ secondPlaneBuffer[secondPlaneIndex] = byte;
1944+ }
1945+ } else {
1946+ // Third plane (G/B data) - combine with first and second planes
1947+ uint32_t thirdPlaneIndex = pixelByteIndex - greenPlaneOffset;
1948+ if (thirdPlaneIndex < secondPlaneSize) {
1949+ uint8_t firstPlaneByte = firstPlaneBuffer[thirdPlaneIndex];
1950+ uint8_t secondPlaneByte = secondPlaneBuffer[thirdPlaneIndex];
1951+ uint8_t invertedFirstPlane = ~firstPlaneByte;
1952+ uint16_t planeY = thirdPlaneIndex / (imgWidth / 8 );
1953+ uint16_t planeX = (thirdPlaneIndex % (imgWidth / 8 )) * 8 ;
1954+
1955+ for (int bit = 7 ; bit >= 0 ; bit--) {
1956+ if (planeY < ((imgHeight < displayWidth) ? imgHeight : displayWidth) && planeX + (7 -bit) < ((imgWidth < displayHeight) ? imgWidth : displayHeight)) {
1957+ bool plane1 = (invertedFirstPlane >> bit) & 0x01 ; // B/W base
1958+ bool plane2 = (secondPlaneByte >> bit) & 0x01 ; // R/Y
1959+ bool plane3 = (byte >> bit) & 0x01 ; // G/B
1960+
1961+ // Decode 6 colors: BLACK=000, WHITE=100, RED=110, YELLOW=010, GREEN=101, BLUE=001
1962+ if (!plane1 && !plane2 && !plane3) {
1963+ epd.drawPixel (displayWidth - planeY, planeX + (7 -bit), BBEP_BLACK);
1964+ } else if (plane1 && !plane2 && !plane3) {
1965+ epd.drawPixel (displayWidth - planeY, planeX + (7 -bit), BBEP_WHITE);
1966+ } else if (plane1 && plane2 && !plane3) {
1967+ epd.drawPixel (displayWidth - planeY, planeX + (7 -bit), BBEP_RED);
1968+ } else if (!plane1 && plane2 && !plane3) {
1969+ epd.drawPixel (displayWidth - planeY, planeX + (7 -bit), BBEP_YELLOW);
1970+ } else if (plane1 && !plane2 && plane3) {
1971+ epd.drawPixel (displayWidth - planeY, planeX + (7 -bit), BBEP_GREEN);
1972+ } else if (!plane1 && !plane2 && plane3) {
1973+ epd.drawPixel (displayWidth - planeY, planeX + (7 -bit), BBEP_BLUE);
1974+ } else {
1975+ // Fallback for unused combinations (111, 011)
1976+ epd.drawPixel (displayWidth - planeY, planeX + (7 -bit), BBEP_BLACK);
1977+ }
1978+ }
1979+ }
1980+ }
1981+ }
17731982 }
17741983 pixelBytesProcessed++;
17751984 }
@@ -1785,11 +1994,19 @@ bool decompressImageDataChunked(){
17851994 writeSerial (" Expected: " + String (originalLength) + " bytes" );
17861995 writeSerial (" Pixel bytes processed: " + String (pixelBytesProcessed));
17871996
1788- // Cleanup allocated buffer
1997+ // Cleanup allocated buffers
17891998 if (firstPlaneBuffer) {
17901999 free (firstPlaneBuffer);
17912000 writeSerial (" Freed first plane buffer" );
17922001 }
2002+ if (secondPlaneBuffer) {
2003+ free (secondPlaneBuffer);
2004+ writeSerial (" Freed second plane buffer" );
2005+ }
2006+ if (thirdPlaneBuffer) {
2007+ free (thirdPlaneBuffer);
2008+ writeSerial (" Freed third plane buffer" );
2009+ }
17932010
17942011 if (res != TINF_DONE && res != TINF_OK) {
17952012 writeSerial (" ERROR: uzlib_uncompress() failed with code " + String (res));
0 commit comments