Skip to content

Commit 3531296

Browse files
authored
Add more color options
1 parent b53c778 commit 3531296

2 files changed

Lines changed: 238 additions & 19 deletions

File tree

src/main.cpp

Lines changed: 235 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -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

16201728
void 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

Comments
 (0)