Added digit dimming and support for .clk format (see https://github.c… (#2555)

* Added digit dimming and support for .clk format (see https://github.com/aly-fly/EleksTubeHAX)

* Small fixes and improvements, dimming optional

Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
This commit is contained in:
RedNax67 2022-03-05 03:10:32 +01:00 committed by GitHub
parent 9c864c9759
commit 4a0a07f158
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 174 additions and 52 deletions

View File

@ -529,12 +529,13 @@ board = esp32dev
platform = espressif32@3.2 platform = espressif32@3.2
upload_speed = 921600 upload_speed = 921600
build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED
#-D ELEKSTUBE_DIMMING # if enabled, scale display brightness (does not set backlight, only scales contents)
-D USERMOD_RTC -D USERMOD_RTC
-D USERMOD_ELEKSTUBE_IPS -D USERMOD_ELEKSTUBE_IPS
-D LEDPIN=12 -D LEDPIN=12
-D RLYPIN=27 -D RLYPIN=27
-D BTNPIN=34 -D BTNPIN=34
-D WLED_DISABLE_INFRARED -D WLED_DISABLE_BLYNK
-D DEFAULT_LED_COUNT=6 -D DEFAULT_LED_COUNT=6
# Display config # Display config
-D ST7789_DRIVER -D ST7789_DRIVER

View File

@ -12,6 +12,7 @@ class TFTs : public TFT_eSPI {
private: private:
uint8_t digits[NUM_DIGITS]; uint8_t digits[NUM_DIGITS];
// These read 16- and 32-bit types from the SD card file. // These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too. // BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere. // May need to reverse subscript order if porting elsewhere.
@ -41,41 +42,70 @@ private:
//// BEGIN STOLEN CODE //// BEGIN STOLEN CODE
// Draw directly from file stored in RGB565 format // Draw directly from file stored in RGB565 format. Fastest
bool drawBin(const char *filename) { bool drawBin(const char *filename) {
fs::File bmpFS; fs::File bmpFS;
// Open requested file on SD card // Open requested file on SD card
bmpFS = WLED_FS.open(filename, "r"); bmpFS = WLED_FS.open(filename, "r");
if (!bmpFS) size_t sz = bmpFS.size();
{ if (sz > 64800) {
Serial.print(F("File not found: ")); bmpFS.close();
Serial.println(filename);
return(false); return(false);
} }
size_t sz = bmpFS.size(); uint16_t r, g, b, dimming = 255;
if (sz <= 64800) int16_t w, h, y, row, col;
{
bool oldSwapBytes = getSwapBytes();
setSwapBytes(true);
int16_t h = sz / (135 * 2); //draw img that is shorter than 240pix into the center
w = 135;
h = sz / (w * 2);
y = (height() - h) /2;
uint8_t lineBuffer[w * 2];
//draw img that is shorter than 240pix into the center if (!realtimeMode || realtimeOverride) strip.service();
int16_t y = (height() - h) /2;
bmpFS.read((uint8_t *) output_buffer,sz); #ifdef ELEKSTUBE_DIMMING
dimming=bri;
#endif
if (!realtimeMode || realtimeOverride) strip.service(); // 0,0 coordinates are top left
for (row = 0; row < h; row++) {
pushImage(0, y, 135, h, (uint16_t *)output_buffer); bmpFS.read(lineBuffer, sizeof(lineBuffer));
uint8_t PixM, PixL;
setSwapBytes(oldSwapBytes);
// Colors are already in 16-bit R5, G6, B5 format
for (col = 0; col < w; col++)
{
if (dimming == 255) { // not needed, copy directly
output_buffer[row][col] = (lineBuffer[col*2+1] << 8) | (lineBuffer[col*2]);
} else {
// 16 BPP pixel format: R5, G6, B5 ; bin: RRRR RGGG GGGB BBBB
PixM = lineBuffer[col*2+1];
PixL = lineBuffer[col*2];
// align to 8-bit value (MSB left aligned)
r = (PixM) & 0xF8;
g = ((PixM << 5) | (PixL >> 3)) & 0xFC;
b = (PixL << 3) & 0xF8;
r *= dimming;
g *= dimming;
b *= dimming;
r = r >> 8;
g = g >> 8;
b = b >> 8;
output_buffer[row][col] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
}
} }
bool oldSwapBytes = getSwapBytes();
setSwapBytes(true);
pushImage(0, y, 135, h, (uint16_t *)output_buffer);
setSwapBytes(oldSwapBytes);
bmpFS.close(); bmpFS.close();
return(true); return(true);
@ -87,16 +117,9 @@ private:
// Open requested file on SD card // Open requested file on SD card
bmpFS = WLED_FS.open(filename, "r"); bmpFS = WLED_FS.open(filename, "r");
if (!bmpFS)
{
Serial.print(F("File not found: "));
Serial.println(filename);
return(false);
}
uint32_t seekOffset; uint32_t seekOffset;
int16_t w, h, row; int16_t w, h, row;
uint8_t r, g, b; uint16_t r, g, b, dimming = 255;
uint16_t magic = read16(bmpFS); uint16_t magic = read16(bmpFS);
if (magic == 0xFFFF) { if (magic == 0xFFFF) {
@ -104,13 +127,6 @@ private:
bmpFS.close(); bmpFS.close();
return(false); return(false);
} }
if (magic != 0x4D42) {
Serial.print(F("File not a BMP. Magic: "));
Serial.println(magic);
bmpFS.close();
return(false);
}
read32(bmpFS); read32(bmpFS);
read32(bmpFS); read32(bmpFS);
@ -128,8 +144,6 @@ private:
//draw img that is shorter than 240pix into the center //draw img that is shorter than 240pix into the center
int16_t y = (height() - h) /2; int16_t y = (height() - h) /2;
bool oldSwapBytes = getSwapBytes();
setSwapBytes(true);
bmpFS.seek(seekOffset); bmpFS.seek(seekOffset);
uint16_t padding = (4 - ((w * 3) & 3)) & 3; uint16_t padding = (4 - ((w * 3) & 3)) & 3;
@ -142,16 +156,29 @@ private:
bmpFS.read(lineBuffer, sizeof(lineBuffer)); bmpFS.read(lineBuffer, sizeof(lineBuffer));
uint8_t* bptr = lineBuffer; uint8_t* bptr = lineBuffer;
#ifdef ELEKSTUBE_DIMMING
dimming=bri;
#endif
// Convert 24 to 16 bit colours while copying to output buffer. // Convert 24 to 16 bit colours while copying to output buffer.
for (uint16_t col = 0; col < w; col++) for (uint16_t col = 0; col < w; col++)
{ {
b = *bptr++; b = *bptr++;
g = *bptr++; g = *bptr++;
r = *bptr++; r = *bptr++;
if (dimming != 255) { // only dimm when needed
b *= dimming;
g *= dimming;
r *= dimming;
b = b >> 8;
g = g >> 8;
r = r >> 8;
}
output_buffer[row][col] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); output_buffer[row][col] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
} }
} }
bool oldSwapBytes = getSwapBytes();
setSwapBytes(true);
pushImage(0, y, w, h, (uint16_t *)output_buffer); pushImage(0, y, w, h, (uint16_t *)output_buffer);
setSwapBytes(oldSwapBytes); setSwapBytes(oldSwapBytes);
@ -159,6 +186,83 @@ private:
return(true); return(true);
} }
bool drawClk(const char *filename) {
fs::File bmpFS;
// Open requested file on SD card
bmpFS = WLED_FS.open(filename, "r");
if (!bmpFS)
{
Serial.print("File not found: ");
Serial.println(filename);
return(false);
}
uint16_t r, g, b, dimming = 255, magic;
int16_t w, h, row, col;
magic = read16(bmpFS);
if (magic != 0x4B43) { // look for "CK" header
Serial.print(F("File not a CLK. Magic: "));
Serial.println(magic);
bmpFS.close();
return(false);
}
w = read16(bmpFS);
h = read16(bmpFS);
int16_t x = (width() - w) / 2;
int16_t y = (height() - h) / 2;
uint8_t lineBuffer[w * 2];
#ifdef ELEKSTUBE_DIMMING
dimming=bri;
#endif
if (!realtimeMode || realtimeOverride) strip.service();
// 0,0 coordinates are top left
for (row = 0; row < h; row++) {
bmpFS.read(lineBuffer, sizeof(lineBuffer));
uint8_t PixM, PixL;
// Colors are already in 16-bit R5, G6, B5 format
for (col = 0; col < w; col++)
{
if (dimming == 255) { // not needed, copy directly
output_buffer[row][col+x] = (lineBuffer[col*2+1] << 8) | (lineBuffer[col*2]);
} else {
// 16 BPP pixel format: R5, G6, B5 ; bin: RRRR RGGG GGGB BBBB
PixM = lineBuffer[col*2+1];
PixL = lineBuffer[col*2];
// align to 8-bit value (MSB left aligned)
r = (PixM) & 0xF8;
g = ((PixM << 5) | (PixL >> 3)) & 0xFC;
b = (PixL << 3) & 0xF8;
r *= dimming;
g *= dimming;
b *= dimming;
r = r >> 8;
g = g >> 8;
b = b >> 8;
output_buffer[row][col+x] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
}
}
bool oldSwapBytes = getSwapBytes();
setSwapBytes(true);
pushImage(0, y, w, h, (uint16_t *)output_buffer);
setSwapBytes(oldSwapBytes);
bmpFS.close();
return(true);
}
public: public:
TFTs() : TFT_eSPI(), chip_select() TFTs() : TFT_eSPI(), chip_select()
{ for (uint8_t digit=0; digit < NUM_DIGITS; digit++) digits[digit] = 0; } { for (uint8_t digit=0; digit < NUM_DIGITS; digit++) digits[digit] = 0; }
@ -184,25 +288,30 @@ public:
chip_select.setDigit(digit); chip_select.setDigit(digit);
if (digits[digit] == blanked) { if (digits[digit] == blanked) {
fillScreen(TFT_BLACK); fillScreen(TFT_BLACK); return;
} }
else {
// Filenames are no bigger than "255.bmp\0" // Filenames are no bigger than "255.bmp\0"
char file_name[10]; char file_name[10];
sprintf(file_name, "/%d.bmp", digits[digit]); // Fastest, raw RGB565
if (WLED_FS.exists(file_name)) { sprintf(file_name, "/%d.bin", digits[digit]);
drawBmp(file_name); if (WLED_FS.exists(file_name)) {
} else { drawBin(file_name); return;
sprintf(file_name, "/%d.bin", digits[digit]);
drawBin(file_name);
}
} }
} // Fast, see https://github.com/aly-fly/EleksTubeHAX on how to create this clk format
sprintf(file_name, "/%d.clk", digits[digit]);
if (WLED_FS.exists(file_name)) {
drawClk(file_name); return;
}
// Slow, regular RGB888 bmp
sprintf(file_name, "/%d.bmp", digits[digit]);
drawBmp(file_name);
}
void setDigit(uint8_t digit, uint8_t value, show_t show=yes) { void setDigit(uint8_t digit, uint8_t value, show_t show=yes) {
uint8_t old_value = digits[digit]; uint8_t old_value = digits[digit];
digits[digit] = value; digits[digit] = value;
if (show != no && (old_value != value || show == force)) { if (show != no && (old_value != value || show == force)) {
showDigit(digit); showDigit(digit);
} }

View File

@ -21,6 +21,8 @@ class ElekstubeIPSUsermod : public Usermod {
set[i] = false; //display HHMMSS time set[i] = false; //display HHMMSS time
} }
} }
uint8_t hr = hour(localTime); uint8_t hr = hour(localTime);
uint8_t hrTens = hr/10; uint8_t hrTens = hr/10;
uint8_t mi = minute(localTime); uint8_t mi = minute(localTime);
@ -37,6 +39,9 @@ class ElekstubeIPSUsermod : public Usermod {
unsigned long lastTime = 0; unsigned long lastTime = 0;
public: public:
uint8_t lastBri;
TFTs::show_t fshow=TFTs::yes;
void setup() { void setup() {
tfts.begin(); tfts.begin();
tfts.fillScreen(TFT_BLACK); tfts.fillScreen(TFT_BLACK);
@ -49,7 +54,14 @@ class ElekstubeIPSUsermod : public Usermod {
void loop() { void loop() {
if (toki.isTick()) { if (toki.isTick()) {
updateLocalTime(); updateLocalTime();
updateClockDisplay(); #ifdef ELEKSTUBE_DIMMING
if (bri != lastBri) {
fshow=TFTs::force;
lastBri = bri;
}
#endif
updateClockDisplay(fshow);
fshow=TFTs::yes;
} }
} }