diff --git a/ESP32_AP-Flasher/data/www/edit.html.gz b/ESP32_AP-Flasher/data/www/edit.html.gz
index b94cbe01..c0333952 100644
Binary files a/ESP32_AP-Flasher/data/www/edit.html.gz and b/ESP32_AP-Flasher/data/www/edit.html.gz differ
diff --git a/ESP32_AP-Flasher/data/www/main.js.gz b/ESP32_AP-Flasher/data/www/main.js.gz
index c13005c6..d1336d6e 100644
Binary files a/ESP32_AP-Flasher/data/www/main.js.gz and b/ESP32_AP-Flasher/data/www/main.js.gz differ
diff --git a/ESP32_AP-Flasher/src/contentmanager.cpp b/ESP32_AP-Flasher/src/contentmanager.cpp
index 99e82c72..f11f84c1 100644
--- a/ESP32_AP-Flasher/src/contentmanager.cpp
+++ b/ESP32_AP-Flasher/src/contentmanager.cpp
@@ -277,7 +277,10 @@ void drawNew(const uint8_t mac[8], tagRecord *&taginfo) {
imageParams.lut = EPD_LUT_DEFAULT;
}
- if (imageParams.zlib) {
+ if (imageParams.bpp == 3) {
+ imageParams.dataType = DATATYPE_IMG_RAW_3BPP;
+ Serial.println("datatype: DATATYPE_IMG_RAW_3BPP");
+ } else if (imageParams.zlib) {
imageParams.dataType = DATATYPE_IMG_ZLIB;
Serial.println("datatype: DATATYPE_IMG_ZLIB");
} else if (imageParams.hasRed) {
@@ -557,7 +560,10 @@ bool updateTagImage(String &filename, const uint8_t *dst, uint16_t nextCheckin,
imageParams.lut = EPD_LUT_DEFAULT;
}
- if (imageParams.zlib) {
+ if (imageParams.bpp == 3) {
+ imageParams.dataType = DATATYPE_IMG_RAW_3BPP;
+ Serial.println("datatype: DATATYPE_IMG_RAW_3BPP");
+ } else if (imageParams.zlib) {
imageParams.dataType = DATATYPE_IMG_ZLIB;
Serial.println("datatype: DATATYPE_IMG_ZLIB");
} else if (imageParams.hasRed) {
@@ -1439,18 +1445,32 @@ bool getCalFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo, imgPa
#ifdef CONTENT_DAYAHEAD
uint16_t getPercentileColor(const double *prices, int numPrices, double price, HwType hwdata) {
- double percentile = 100.0;
- int colorIndex = 3;
- const char *colors[] = {"black", "darkgray", "pink", "red"};
- if (hwdata.highlightColor == 3) {
- // yellow
- colors[2] = "brown";
- colors[3] = "yellow";
- }
- const int numColors = sizeof(colors) / sizeof(colors[0]);
+ const char *colorsDefault[] = {"black", "darkgray", "pink", "red"};
+ const double boundariesDefault[] = {40.0, 80.0, 90.0};
- const double boundaries[] = {40.0, 80.0, 90.0};
- const int numBoundaries = sizeof(boundaries) / sizeof(boundaries[0]);
+ const char *colors3bpp[] = {"blue", "green", "yellow", "orange", "red"};
+ const double boundaries3bpp[] = {20.0, 50.0, 70.0, 90.0};
+
+ const char **colors;
+ const double *boundaries;
+ int numColors, numBoundaries;
+
+ if (hwdata.bpp == 3) {
+ colors = colors3bpp;
+ boundaries = boundaries3bpp;
+ numColors = sizeof(colors3bpp) / sizeof(colors3bpp[0]);
+ numBoundaries = sizeof(boundaries3bpp) / sizeof(boundaries3bpp[0]);
+ } else {
+ colors = colorsDefault;
+ boundaries = boundariesDefault;
+ numColors = sizeof(colorsDefault) / sizeof(colorsDefault[0]);
+ numBoundaries = sizeof(boundariesDefault) / sizeof(boundariesDefault[0]);
+ if (hwdata.highlightColor == 3) {
+ colors[2] = "brown";
+ colors[3] = "yellow";
+ }
+ }
+ int colorIndex = numColors - 1;
for (int i = 0; i < numBoundaries; i++) {
if (price < prices[int(numPrices * boundaries[i] / 100.0)]) {
@@ -1622,7 +1642,7 @@ bool getDayAheadFeed(String &filename, JsonObject &cfgobj, tagRecord *&taginfo,
spr.fillTriangle(barX + i * barwidth, 15 + arrowY,
barX + i * barwidth + barwidth - 1, 15 + arrowY,
barX + i * barwidth + (barwidth - 1) / 2, 15 + barwidth + arrowY, imageParams.highlightColor);
- spr.drawLine(barX + i * barwidth + (barwidth - 1) / 2, 20 + barwidth + arrowY, barX + i * barwidth + (barwidth - 1) / 2, spr.height(), getColor("pink"));
+ spr.drawLine(barX + i * barwidth + (barwidth - 1) / 2, 20 + barwidth + arrowY, barX + i * barwidth + (barwidth - 1) / 2, spr.height(), TFT_BLACK);
pricenow = price;
}
}
@@ -2217,6 +2237,9 @@ uint16_t getColor(const String &color) {
if (color == "5" || color == "darkgray") return TFT_DARKGREY;
if (color == "6" || color == "pink") return 0xFBCF;
if (color == "7" || color == "brown") return 0x8400;
+ if (color == "8" || color == "green") return TFT_GREEN;
+ if (color == "9" || color == "blue") return TFT_BLUE;
+ if (color == "10" || color == "orange") return 0xFBE0;
uint16_t r, g, b;
if (color.length() == 7 && color[0] == '#' &&
sscanf(color.c_str(), "#%2hx%2hx%2hx", &r, &g, &b) == 3) {
diff --git a/ESP32_AP-Flasher/src/makeimage.cpp b/ESP32_AP-Flasher/src/makeimage.cpp
index b02a1a3e..5371dcaf 100644
--- a/ESP32_AP-Flasher/src/makeimage.cpp
+++ b/ESP32_AP-Flasher/src/makeimage.cpp
@@ -112,6 +112,7 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
{12, 5, 14, 6},
{3, 11, 1, 8},
{15, 7, 13, 4}};
+ size_t bitOffset = 0;
memset(error_bufferold, 0, bufw * sizeof(Error));
for (uint16_t y = 0; y < bufh; y++) {
@@ -134,10 +135,10 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
if (imageParams.dither == 2) {
// Ordered dithering
- uint8_t ditherValue = ditherMatrix[y % 4][x % 4];
- error_bufferold[x].r = (ditherValue << 4) - 120; // * 256 / 16 - 128 + 8
- error_bufferold[x].g = (ditherValue << 4) - 120;
- error_bufferold[x].b = (ditherValue << 4) - 120;
+ uint8_t ditherValue = ditherMatrix[y % 4][x % 4] << (imageParams.bpp == 3 ? 2 : 4);
+ error_bufferold[x].r = ditherValue - (imageParams.bpp == 3 ? 30 : 120); // * 256 / 16 - 128 + 8
+ error_bufferold[x].g = ditherValue - (imageParams.bpp == 3 ? 30 : 120);
+ error_bufferold[x].b = ditherValue - (imageParams.bpp == 3 ? 30 : 120);
}
int best_color_index = 0;
@@ -151,24 +152,40 @@ void spr2color(TFT_eSprite &spr, imgParam &imageParams, uint8_t *buffer, size_t
best_color_index = i;
}
}
- uint8_t bitIndex = 7 - (x % 8);
- uint32_t byteIndex = (y * bufw + x) / 8;
- // this looks a bit ugly, but it's performing better than shorter notations
- switch (best_color_index) {
- case 1:
- if (!is_red)
+ if (imageParams.bpp == 3) {
+ size_t byteIndex = bitOffset / 8;
+ uint8_t bitIndex = bitOffset % 8;
+
+ if (bitIndex + imageParams.bpp <= 8) {
+ buffer[byteIndex] |= best_color_index << (8 - bitIndex - imageParams.bpp);
+ } else {
+ uint8_t highPart = best_color_index >> (bitIndex + imageParams.bpp - 8);
+ uint8_t lowPart = best_color_index & ((1 << (bitIndex + imageParams.bpp - 8)) - 1);
+ buffer[byteIndex] |= highPart;
+ buffer[byteIndex + 1] |= lowPart << (8 - (bitIndex + imageParams.bpp - 8));
+ }
+ bitOffset += imageParams.bpp;
+ } else {
+ uint8_t bitIndex = 7 - (x % 8);
+ uint32_t byteIndex = (y * bufw + x) / 8;
+
+ // this looks a bit ugly, but it's performing better than shorter notations
+ switch (best_color_index) {
+ case 1:
+ if (!is_red)
+ buffer[byteIndex] |= (1 << bitIndex);
+ break;
+ case 2:
+ imageParams.hasRed = true;
+ if (is_red)
+ buffer[byteIndex] |= (1 << bitIndex);
+ break;
+ case 3:
+ imageParams.hasRed = true;
buffer[byteIndex] |= (1 << bitIndex);
- break;
- case 2:
- imageParams.hasRed = true;
- if (is_red)
- buffer[byteIndex] |= (1 << bitIndex);
- break;
- case 3:
- imageParams.hasRed = true;
- buffer[byteIndex] |= (1 << bitIndex);
- break;
+ break;
+ }
}
if (imageParams.dither == 1) {
@@ -226,7 +243,10 @@ size_t prepareHeader(uint8_t headerbuf[], uint16_t bufw, uint16_t bufh, imgParam
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 3 : 1), &bufw, sizeof(uint16_t));
memcpy(headerbuf + (imageParams.rotatebuffer % 2 == 1 ? 1 : 3), &bufh, sizeof(uint16_t));
- if (imageParams.hasRed && imageParams.bpp > 1) {
+ if (imageParams.bpp == 3) {
+ totalbytes = buffer_size * 3 + headersize;
+ headerbuf[5] = 3;
+ } else if (imageParams.hasRed && imageParams.bpp > 1) {
totalbytes = buffer_size * 2 + headersize;
headerbuf[5] = 2;
} else {
@@ -370,6 +390,23 @@ void spr2buffer(TFT_eSprite &spr, String &fileout, imgParam &imageParams) {
free(buffer);
} break;
+ case 3: {
+ long bufw = spr.width(), bufh = spr.height();
+ size_t buffer_size = (bufw * bufh) / 8 * 3;
+ uint8_t *buffer = (uint8_t *)ps_malloc(buffer_size);
+ if (!buffer) {
+ Serial.println("Failed to allocate buffer");
+ util::printLargestFreeBlock();
+ f_out.close();
+ xSemaphoreGive(fsMutex);
+ return;
+ }
+ spr2color(spr, imageParams, buffer, buffer_size, false);
+ f_out.write(buffer, buffer_size);
+
+ free(buffer);
+ } break;
+
case 16: {
size_t spriteDataSize = (spr.getColorDepth() == 1) ? (spr.width() * spr.height() / 8) : ((spr.getColorDepth() == 8) ? (spr.width() * spr.height()) : ((spr.getColorDepth() == 16) ? (spr.width() * spr.height() * 2) : 0));
f_out.write((const uint8_t *)spr.getPointer(), spriteDataSize);
diff --git a/ESP32_AP-Flasher/src/newproto.cpp b/ESP32_AP-Flasher/src/newproto.cpp
index a2edb8c9..9fd3cb3d 100644
--- a/ESP32_AP-Flasher/src/newproto.cpp
+++ b/ESP32_AP-Flasher/src/newproto.cpp
@@ -273,7 +273,8 @@ void prepareExternalDataAvail(struct pendingData* pending, IPAddress remoteIP) {
case DATATYPE_IMG_DIFF:
case DATATYPE_IMG_ZLIB:
case DATATYPE_IMG_RAW_1BPP:
- case DATATYPE_IMG_RAW_2BPP: {
+ case DATATYPE_IMG_RAW_2BPP:
+ case DATATYPE_IMG_RAW_3BPP: {
char hexmac[17];
mac2hex(pending->targetMac, hexmac);
String filename = "/current/" + String(hexmac) + "_" + String(millis() % 1000000) + ".pending";
@@ -445,7 +446,7 @@ void processXferComplete(struct espXferComplete* xfc, bool local) {
contentFS->remove(dst_path);
}
if (contentFS->exists(queueItem->filename)) {
- if (config.preview && (queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_ZLIB)) {
+ if (config.preview && (queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_3BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || queueItem->pendingdata.availdatainfo.dataType == DATATYPE_IMG_ZLIB)) {
contentFS->rename(queueItem->filename, String(dst_path));
} else {
if (queueItem->pendingdata.availdatainfo.dataType != DATATYPE_FW_UPDATE) contentFS->remove(queueItem->filename);
@@ -966,7 +967,7 @@ bool queueDataAvail(struct pendingData* pending, bool local) {
}
newPending.len = taginfo->len;
- if ((pending->availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || pending->availdatainfo.dataType == DATATYPE_IMG_ZLIB) && (pending->availdatainfo.dataTypeArgument & 0xF8) == 0x00) {
+ if ((pending->availdatainfo.dataType == DATATYPE_IMG_RAW_1BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_2BPP || pending->availdatainfo.dataType == DATATYPE_IMG_RAW_3BPP || pending->availdatainfo.dataType == DATATYPE_IMG_ZLIB) && (pending->availdatainfo.dataTypeArgument & 0xF8) == 0x00) {
// in case of an image (no preload), remove already queued images
pendingQueue.erase(std::remove_if(pendingQueue.begin(), pendingQueue.end(),
[pending](const PendingItem& item) {
diff --git a/ESP32_AP-Flasher/wwwroot/edit.html b/ESP32_AP-Flasher/wwwroot/edit.html
index bfeec7ea..3e7c7109 100644
--- a/ESP32_AP-Flasher/wwwroot/edit.html
+++ b/ESP32_AP-Flasher/wwwroot/edit.html
@@ -452,7 +452,27 @@
imageData.data[i * 4 + 2] = is16Bit ? (rgb & 0x1F) << 3 : ((rgb & 0x03) << 6) * 1.3;
imageData.data[i * 4 + 3] = 255;
}
+ } else if (tagTypes[hwtype].bpp == 3) {
+ const colorTable = tagTypes[hwtype].colortable;
+ let pixelIndex = 0;
+ for (let i = 0; i < data.length; i += 3) {
+ for (let j = 0; j < 8; j++) {
+ let bitPos = j * 3;
+ let bytePos = Math.floor(bitPos / 8);
+ let bitOffset = bitPos % 8;
+ let pixelValue = (data[i + bytePos] >> (5 - bitOffset)) & 0x07;
+ if (bitOffset > 5) {
+ pixelValue = ((data[i + bytePos] & (0xFF >> bitOffset)) << (bitOffset - 5)) |
+ (data[i + bytePos + 1] >> (13 - bitOffset));
+ }
+ imageData.data[pixelIndex * 4] = colorTable[pixelValue][0];
+ imageData.data[pixelIndex * 4 + 1] = colorTable[pixelValue][1];
+ imageData.data[pixelIndex * 4 + 2] = colorTable[pixelValue][2];
+ imageData.data[pixelIndex * 4 + 3] = 255;
+ pixelIndex++;
+ }
+ }
} else {
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
diff --git a/ESP32_AP-Flasher/wwwroot/main.js b/ESP32_AP-Flasher/wwwroot/main.js
index b8eab990..b6afee26 100644
--- a/ESP32_AP-Flasher/wwwroot/main.js
+++ b/ESP32_AP-Flasher/wwwroot/main.js
@@ -1243,6 +1243,28 @@ function drawCanvas(buffer, canvas, hwtype, tagmac, doRotate) {
imageData.data[i * 4 + 3] = 255;
}
+ } else if (tagTypes[hwtype].bpp == 3) {
+ const colorTable = tagTypes[hwtype].colortable;
+
+ let pixelIndex = 0;
+ for (let i = 0; i < data.length; i += 3) {
+ for (let j = 0; j < 8; j++) {
+ let bitPos = j * 3;
+ let bytePos = Math.floor(bitPos / 8);
+ let bitOffset = bitPos % 8;
+ let pixelValue = (data[i + bytePos] >> (5 - bitOffset)) & 0x07;
+ if (bitOffset > 5) {
+ pixelValue = ((data[i + bytePos] & (0xFF >> bitOffset)) << (bitOffset - 5)) |
+ (data[i + bytePos + 1] >> (13 - bitOffset));
+ }
+ imageData.data[pixelIndex * 4] = colorTable[pixelValue][0];
+ imageData.data[pixelIndex * 4 + 1] = colorTable[pixelValue][1];
+ imageData.data[pixelIndex * 4 + 2] = colorTable[pixelValue][2];
+ imageData.data[pixelIndex * 4 + 3] = 255;
+ pixelIndex++;
+ }
+ }
+
} else {
const offsetRed = (data.length >= (canvas.width * canvas.height / 8) * 2) ? canvas.width * canvas.height / 8 : 0;
diff --git a/oepl-definitions.h b/oepl-definitions.h
index 7800778c..18ea7457 100755
--- a/oepl-definitions.h
+++ b/oepl-definitions.h
@@ -117,6 +117,7 @@
#define DATATYPE_IMG_DIFF 0x10 // always 1BPP ** deprecated
#define DATATYPE_IMG_RAW_1BPP 0x20 // 2888 bytes for 1.54" / 4736 2.9" / 15000 4.2"
#define DATATYPE_IMG_RAW_2BPP 0x21 // 5776 bytes for 1.54" / 9472 2.9" / 30000 4.2"
+#define DATATYPE_IMG_RAW_3BPP 0x22 // ACEP
#define DATATYPE_IMG_ZLIB 0x30 // compressed format.
// [uint32_t uncompressed size][2 byte zlib header][zlib compressed image]
// image format: [uint8_t header length][uint16_t width][uint16_t height][uint8_t bpp (lower 4)][img data]
diff --git a/resources/tagtypes/05.json b/resources/tagtypes/05.json
index 5a73e269..0f992338 100644
--- a/resources/tagtypes/05.json
+++ b/resources/tagtypes/05.json
@@ -1,5 +1,5 @@
{
- "version": 3,
+ "version": 4,
"name": "M2 7.4\"",
"width": 640,
"height": 384,
@@ -54,7 +54,7 @@
"gridparam": [ 3, 17, 30, "calibrib16.vlw", "tahoma9.vlw", 14 ]
},
"27": {
- "bars": [ 18, 612, 350, 20 ],
+ "bars": [ 18, 612, 330, 20, 22 ],
"time": [ "calibrib16.vlw" ],
"yaxis": [ "calibrib16.vlw", 1, 12 ],
"head": [ "calibrib30.vlw" ]