diff --git a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp
index dbfd00e2d..5e88150cc 100644
--- a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp
+++ b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.cpp
@@ -1243,6 +1243,16 @@ void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) {
textsize_y = (s_y > 0) ? s_y : 1;
}
+void Adafruit_GFX::setwidth(uint16_t w) {
+ WIDTH = w;
+ _width = w;
+}
+
+void Adafruit_GFX::setheight(uint16_t h) {
+ HEIGHT = h;
+ _height = h;
+}
+
/**************************************************************************/
/*!
@brief Set rotation setting for display
diff --git a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.h b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.h
index dc970b26d..8af31324e 100644
--- a/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.h
+++ b/lib/lib_display/Adafruit-GFX-Library-1.5.6-gemu-1.0/Adafruit_GFX.h
@@ -187,6 +187,10 @@ virtual void
/************************************************************************/
int16_t height(void) const { return _height; }
+ void setwidth(uint16_t w);
+
+ void setheight(uint16_t h);
+
/************************************************************************/
/*!
@brief Get rotation setting for display
diff --git a/lib/lib_display/UDisplay/keywords.txt b/lib/lib_display/UDisplay/keywords.txt
new file mode 100644
index 000000000..bb1efcdcc
--- /dev/null
+++ b/lib/lib_display/UDisplay/keywords.txt
@@ -0,0 +1,30 @@
+#######################################
+# Syntax Coloring Map
+#######################################
+
+#######################################
+# Datatypes (KEYWORD1)
+#######################################
+
+ST7789 KEYWORD1
+
+
+#######################################
+# Methods and Functions (KEYWORD2)
+#######################################
+
+setRotation KEYWORD2
+setAddrWindow KEYWORD2
+pushColor KEYWORD2
+drawPixel KEYWORD2
+drawFastVLine KEYWORD2
+drawFastHLine KEYWORD2
+fillRect KEYWORD2
+setRotation KEYWORD2
+setRotation KEYWORD2
+height KEYWORD2
+width KEYWORD2
+invertDisplay KEYWORD2
+drawImage KEYWORD2
+setScrollArea KEYWORD2
+scroll KEYWORD2
diff --git a/lib/lib_display/UDisplay/library.properties b/lib/lib_display/UDisplay/library.properties
new file mode 100644
index 000000000..c7dd23a3a
--- /dev/null
+++ b/lib/lib_display/UDisplay/library.properties
@@ -0,0 +1,9 @@
+name=universal display Library
+version=0.1
+author=Gerhard Mutz
+maintainer=Gerhard Mutz
+sentence=This is a library a couple of displays.
+paragraph=This is a library a couple of displays.
+category=Display
+url=https://github.com/arendst/Tasmota
+architectures=*
diff --git a/lib/lib_display/UDisplay/uDisplay.cpp b/lib/lib_display/UDisplay/uDisplay.cpp
new file mode 100644
index 000000000..0c15c8712
--- /dev/null
+++ b/lib/lib_display/UDisplay/uDisplay.cpp
@@ -0,0 +1,607 @@
+/*
+ uDisplay.cpp - universal display driver support for Tasmota
+
+ Copyright (C) 2021 Gerhard Mutz and Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#include
+#include
+#include
+#include "uDisplay.h"
+
+
+const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\
+ UDISP_YELLOW,UDISP_NAVY,UDISP_DARKGREEN,UDISP_DARKCYAN,UDISP_MAROON,UDISP_PURPLE,UDISP_OLIVE,\
+UDISP_LIGHTGREY,UDISP_DARKGREY,UDISP_ORANGE,UDISP_GREENYELLOW,UDISP_PINK};
+
+uint16_t uDisplay::GetColorFromIndex(uint8_t index) {
+ if (index >= sizeof(udisp_colors) / 2) index = 0;
+ return udisp_colors[index];
+}
+
+extern uint8_t *buffer;
+
+uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
+ // analyse decriptor
+ uint8_t section = 0;
+ dsp_ncmds = 0;
+ char linebuff[128];
+ while (*lp) {
+
+ uint16_t llen = strlen_ln(lp);
+ strncpy(linebuff, lp, llen);
+ linebuff[llen] = 0;
+ lp += llen;
+ char *lp1 = linebuff;
+
+ if (*lp1 == '#') break;
+ if (*lp1 == '\n') lp1++;
+ while (*lp1 == ' ') lp1++;
+ //Serial.printf(">> %s\n",lp1);
+ if (*lp1 != ';') {
+ // check ids:
+ if (*lp1 == ':') {
+ // id line
+ lp1++;
+ section = *lp1++;
+ } else {
+ switch (section) {
+ case 'H':
+ // header line
+ // SD1306,128,64,1,I2C,5a,*,*,*
+ str2c(&lp1, dname, sizeof(dname));
+ char ibuff[16];
+ gxs = next_val(&lp1);
+ setwidth(gxs);
+ gys = next_val(&lp1);
+ setheight(gys);
+ bpp = next_val(&lp1);
+ str2c(&lp1, ibuff, sizeof(ibuff));
+ if (!strncmp(ibuff, "I2C", 3)) {
+ interface = _UDSP_I2C;
+ i2caddr = next_hex(&lp1);
+ i2c_scl = next_val(&lp1);
+ i2c_sda = next_val(&lp1);
+ reset = next_val(&lp1);
+ section = 0;
+ } else if (!strncmp(ibuff, "SPI", 3)) {
+ interface = _UDSP_SPI;
+ spi_nr = next_val(&lp1);
+ spi_cs = next_val(&lp1);
+ spi_clk = next_val(&lp1);
+ spi_mosi = next_val(&lp1);
+ spi_dc = next_val(&lp1);
+ bpanel = next_val(&lp1);
+ reset = next_val(&lp1);
+ spi_miso = next_val(&lp1);
+ spi_speed = next_val(&lp1);
+
+ section = 0;
+ Serial.printf("%d %d %d %d %d %d %d %d\n", spi_cs, spi_clk, spi_mosi, spi_dc, bpanel, reset, spi_miso, spi_speed);
+ }
+ break;
+ case 'S':
+ splash_font = next_val(&lp1);
+ splash_size = next_val(&lp1);
+ fg_col = next_val(&lp1);
+ if (bpp == 16) {
+ fg_col = GetColorFromIndex(fg_col);
+ }
+ bg_col = next_val(&lp1);
+ if (bpp == 16) {
+ bg_col = GetColorFromIndex(bg_col);
+ }
+ splash_xp = next_val(&lp1);
+ splash_yp = next_val(&lp1);
+ break;
+ case 'I':
+ // init data
+ if (interface == _UDSP_I2C) {
+ dsp_cmds[dsp_ncmds++] = next_hex(&lp1);
+ if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
+ dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
+ }
+ } else {
+ while (1) {
+ if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
+ dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
+ } else {
+ break;
+ }
+ if (dsp_ncmds >= sizeof(dsp_cmds)) break;
+
+ }
+ }
+ break;
+ case 'o':
+ str2c(&lp1, ibuff, sizeof(ibuff));
+ dsp_off = strtol(ibuff, 0, 16);
+ break;
+ case 'O':
+ str2c(&lp1, ibuff, sizeof(ibuff));
+ dsp_on = strtol(ibuff, 0, 16);
+ break;
+ case '0':
+ rot_0 = next_hex(&lp1);
+ break;
+ case '1':
+ rot_1 = next_hex(&lp1);
+ break;
+ case '2':
+ rot_2 = next_hex(&lp1);
+ break;
+ case '3':
+ rot_3 = next_hex(&lp1);
+ break;
+ case 'A':
+ saw_1 = next_hex(&lp1);
+ saw_2 = next_hex(&lp1);
+ saw_3 = next_hex(&lp1);
+ break;
+ }
+ }
+ }
+ if (*lp == '\n') {
+ lp++;
+ } else {
+ lp = strchr(lp, '\n');
+ if (!lp) break;
+ lp++;
+ }
+ }
+}
+
+
+Renderer *uDisplay::Init(void) {
+
+
+ if (reset >= 0) {
+ pinMode(reset, OUTPUT);
+ digitalWrite(reset, HIGH);
+ delay(50);
+ digitalWrite(reset, LOW);
+ delay(50);
+ digitalWrite(reset, HIGH);
+ delay(200);
+ }
+
+ if (interface == _UDSP_I2C) {
+ Wire.begin(i2c_sda, i2c_scl);
+ if (bpp < 16) {
+ if (buffer) free(buffer);
+ buffer = (uint8_t*)calloc((width()*height()*bpp)/8, 1);
+
+ for (uint32_t cnt = 0; cnt < dsp_ncmds; cnt++) {
+ i2c_command(dsp_cmds[cnt]);
+ }
+ }
+ }
+ if (interface == _UDSP_SPI) {
+ if (bpanel >= 0) {
+#ifdef ESP32
+ ledcSetup(ESP32_PWM_CHANNEL, 4000, 8);
+ ledcAttachPin(bpanel, ESP32_PWM_CHANNEL);
+ ledcWrite(ESP32_PWM_CHANNEL, 128);
+#else
+ pinMode(bpanel, OUTPUT);
+ digitalWrite(bpanel, HIGH);
+#endif // ESP32
+ }
+ if (spi_dc >= 0) {
+ pinMode(spi_dc, OUTPUT);
+ digitalWrite(spi_dc, HIGH);
+ }
+ if (spi_cs >= 0) {
+ pinMode(spi_cs, OUTPUT);
+ digitalWrite(spi_cs, HIGH);
+ }
+
+ spiSettings = SPISettings(spi_speed, MSBFIRST, SPI_MODE3);
+
+#ifdef ESP8266
+ SPI.begin();
+ uspi = &SPI;
+#else
+ if (spi_nr != 1) {
+ uspi = new SPIClass(HSPI);
+ } else {
+ uspi = &SPI;
+ }
+ uspi->begin(spi_clk, spi_miso, spi_mosi, -1);
+#endif
+
+ uint16_t index = 0;
+
+ SPI_BEGIN_TRANSACTION
+ while (1) {
+ uint8_t iob;
+ SPI_CS_LOW
+ SPI_DC_LOW
+ iob = dsp_cmds[index++];
+ uspi->write(iob);
+ SPI_DC_HIGH
+ uint8_t args = dsp_cmds[index++];
+ //Serial.printf("cmd, args %x, %d ", iob, args&0x7f);
+ for (uint32_t cnt = 0; cnt < (args & 0x7f); cnt++) {
+ iob = dsp_cmds[index++];
+ //Serial.printf("%02x ", iob );
+ uspi->write(iob);
+ }
+ SPI_CS_HIGH
+ //Serial.printf("\n");
+ if (args & 0x80) delay(120);
+ if (index >= dsp_ncmds) break;
+ }
+ SPI_END_TRANSACTION
+
+ }
+ return this;
+}
+
+void uDisplay::DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font) {
+ setRotation(rot);
+ invertDisplay(false);
+ setTextWrap(false);
+ cp437(true);
+ setTextFont(font);
+ setTextSize(size);
+ setTextColor(fg_col, bg_col);
+ setCursor(0,0);
+ fillScreen(bg_col);
+ Updateframe();
+}
+
+void uDisplay::spi_command(uint8_t val) {
+ SPI_BEGIN_TRANSACTION
+ SPI_DC_LOW
+ SPI_CS_LOW
+ uspi->write(val);
+ SPI_CS_HIGH
+ SPI_DC_HIGH
+ SPI_END_TRANSACTION
+}
+
+void uDisplay::i2c_command(uint8_t val) {
+ //Serial.printf("%02x\n",val );
+ Wire.beginTransmission(i2caddr);
+ Wire.write(0);
+ Wire.write(val);
+ Wire.endTransmission();
+}
+
+#define SH1106_SETLOWCOLUMN 0
+#define SH1106_SETHIGHCOLUMN 0x10
+#define SH1106_SETSTARTLINE 0x40
+
+
+void uDisplay::Updateframe(void) {
+
+ if (interface == _UDSP_I2C) {
+ i2c_command(SH1106_SETLOWCOLUMN | 0x0); // low col = 0
+ i2c_command(SH1106_SETHIGHCOLUMN | 0x0); // hi col = 0
+ i2c_command(SH1106_SETSTARTLINE | 0x0); // line #0
+
+ uint8_t ys = gys >> 3;
+ uint8_t xs = gxs >> 3;
+ //uint8_t xs = 132 >> 3;
+ uint8_t m_row = 0;
+ uint8_t m_col = 2;
+
+ uint16_t p = 0;
+
+ uint8_t i, j, k = 0;
+
+ for ( i = 0; i < ys; i++) {
+ // send a bunch of data in one xmission
+ i2c_command(0xB0 + i + m_row);//set page address
+ i2c_command(m_col & 0xf);//set lower column address
+ i2c_command(0x10 | (m_col >> 4));//set higher column address
+
+ for( j = 0; j < 8; j++){
+ Wire.beginTransmission(i2caddr);
+ Wire.write(0x40);
+ for ( k = 0; k < xs; k++, p++) {
+ Wire.write(buffer[p]);
+ }
+ Wire.endTransmission();
+ }
+ }
+ }
+}
+
+void uDisplay::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) {
+
+ if (interface != _UDSP_SPI) {
+ Renderer::drawFastVLine(x, y, h, color);
+ return;
+ }
+ // Rudimentary clipping
+ if ((x >= _width) || (y >= _height)) return;
+ if ((y + h - 1) >= _height) h = _height - y;
+
+ SPI_BEGIN_TRANSACTION
+
+ SPI_CS_LOW
+
+ setAddrWindow_int(x, y, 1, h);
+
+ while (h--) {
+ uspi->write16(color);
+ }
+
+ SPI_CS_HIGH
+
+ SPI_END_TRANSACTION
+}
+
+void uDisplay::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) {
+
+ if (interface != _UDSP_SPI) {
+ Renderer::drawFastHLine(x, y, w, color);
+ return;
+ }
+
+ // Rudimentary clipping
+ if((x >= _width) || (y >= _height)) return;
+ if((x+w-1) >= _width) w = _width-x;
+
+
+ SPI_BEGIN_TRANSACTION
+
+ SPI_CS_LOW
+
+ setAddrWindow_int(x, y, w, 1);
+
+
+ while (w--) {
+ uspi->write16(color);
+ }
+
+ SPI_CS_HIGH
+
+ SPI_END_TRANSACTION
+}
+
+void uDisplay::fillScreen(uint16_t color) {
+ fillRect(0, 0, gxs, gys, color);
+}
+
+// fill a rectangle
+void uDisplay::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) {
+
+ if (interface != _UDSP_SPI) {
+ Renderer::fillRect(x, y, w, h, color);
+ return;
+ }
+
+ // rudimentary clipping (drawChar w/big text requires this)
+ if((x >= gxs) || (y >= gys)) return;
+ if((x + w - 1) >= gxs) w = gxs - x;
+ if((y + h - 1) >= gys) h = gys - y;
+
+
+ SPI_BEGIN_TRANSACTION
+ SPI_CS_LOW
+
+ setAddrWindow_int(x, y, w, h);
+
+ for (y = h; y > 0; y--) {
+ for (x = w; x > 0; x--) {
+ uspi->write16(color);
+ }
+ }
+ SPI_CS_HIGH
+ SPI_END_TRANSACTION
+}
+
+
+void uDisplay::Splash(void) {
+ setTextFont(splash_font);
+ setTextSize(splash_size);
+ DrawStringAt(splash_xp, splash_yp, dname, fg_col, 0);
+ Updateframe();
+}
+
+void uDisplay::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) {
+
+ if (!x0 && !y0 && !x1 && !y1) {
+ SPI_CS_HIGH
+ SPI_END_TRANSACTION
+ } else {
+ SPI_CS_LOW
+ SPI_BEGIN_TRANSACTION
+ setAddrWindow_int(x0, y0, x1 - x0, y1 - y0 );
+ }
+}
+
+void uDisplay::setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
+ uint32_t xa = ((uint32_t)x << 16) | (x+w-1);
+ uint32_t ya = ((uint32_t)y << 16) | (y+h-1);
+
+ SPI_DC_LOW
+ uspi->write(saw_1);
+ SPI_DC_HIGH
+
+ uspi->write32(xa);
+
+ SPI_DC_LOW
+ uspi->write(saw_2);
+ SPI_DC_HIGH
+
+ uspi->write32(ya);
+
+ SPI_DC_LOW
+ uspi->write(saw_3); // write to RAM
+ SPI_DC_HIGH
+
+}
+
+void uDisplay::pushColors(uint16_t *data, uint16_t len, boolean first) {
+ uint16_t color;
+
+ while (len--) {
+ color = *data++;
+ uspi->write16(color);
+ }
+
+}
+
+void uDisplay::drawPixel(int16_t x, int16_t y, uint16_t color) {
+
+ if (interface != _UDSP_SPI) {
+ Renderer::drawPixel(x, y, color);
+ return;
+ }
+
+ if((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return;
+
+
+ SPI_BEGIN_TRANSACTION
+
+ SPI_CS_LOW
+
+ setAddrWindow_int(x, y, 1, 1);
+
+ uspi->write16(color);
+
+ SPI_CS_HIGH
+
+ SPI_END_TRANSACTION
+}
+
+void uDisplay::setRotation(uint8_t m) {
+ if (interface != _UDSP_SPI) {
+ Renderer::setRotation(m);
+ return;
+ }
+ switch (rotation) {
+ case 0:
+ if (interface == _UDSP_SPI) spi_command(rot_0);
+ _width = gxs;
+ _height = gys;
+ break;
+ case 1:
+ if (interface == _UDSP_SPI) spi_command(rot_1);
+ _width = gys;
+ _height = gxs;
+ break;
+ case 2:
+ if (interface == _UDSP_SPI) spi_command(rot_2);
+ _width = gxs;
+ _height = gys;
+ break;
+ case 3:
+ if (interface == _UDSP_SPI) spi_command(rot_3);
+ _width = gys;
+ _height = gxs;
+ break;
+ }
+}
+
+void uDisplay::DisplayOnff(int8_t on) {
+
+ if (interface == _UDSP_I2C) {
+ if (on) {
+ i2c_command(dsp_on);
+ } else {
+ i2c_command(dsp_off);
+ }
+ } else {
+ if (on) {
+ spi_command(dsp_on);
+ if (bpanel >= 0) {
+#ifdef ESP32
+ ledcWrite(ESP32_PWM_CHANNEL, dimmer);
+#else
+ digitalWrite(bpanel, HIGH);
+#endif
+ }
+
+ } else {
+ spi_command(dsp_off);
+ if (bpanel >= 0) {
+#ifdef ESP32
+ ledcWrite(ESP32_PWM_CHANNEL, 0);
+#else
+ digitalWrite(bpanel, LOW);
+#endif
+ }
+ }
+ }
+}
+
+void uDisplay::dim(uint8_t dim) {
+ dimmer = dim;
+ if (dimmer > 15) dimmer = 15;
+ dimmer = ((float)dimmer / 15.0) * 255.0;
+#ifdef ESP32
+ ledcWrite(ESP32_PWM_CHANNEL, dimmer);
+#endif
+}
+
+
+
+uint8_t uDisplay::strlen_ln(char *str) {
+ for (uint32_t cnt = 0; cnt < 256; cnt++) {
+ if (!str[cnt] || str[cnt] == '\n') return cnt;
+ }
+ return 0;
+}
+
+char *uDisplay::devname(void) {
+ return dname;
+}
+
+uint32_t uDisplay::str2c(char **sp, char *vp, uint32_t len) {
+ char *lp = *sp;
+ if (len) len--;
+ char *cp = strchr(lp, ',');
+ if (cp) {
+ while (1) {
+ if (*lp == ',') {
+ *vp = 0;
+ *sp = lp + 1;
+ return 0;
+ }
+ if (len) {
+ *vp++ = *lp++;
+ len--;
+ } else {
+ lp++;
+ }
+ }
+ } else {
+ uint8_t slen = strlen(lp);
+ if (slen) {
+ strlcpy(vp, *sp, len);
+ *sp = lp + slen;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int32_t uDisplay::next_val(char **sp) {
+ char ibuff[16];
+ str2c(sp, ibuff, sizeof(ibuff));
+ return atoi(ibuff);
+}
+
+uint32_t uDisplay::next_hex(char **sp) {
+ char ibuff[16];
+ str2c(sp, ibuff, sizeof(ibuff));
+ return strtol(ibuff, 0, 16);
+}
diff --git a/lib/lib_display/UDisplay/uDisplay.h b/lib/lib_display/UDisplay/uDisplay.h
new file mode 100644
index 000000000..f5f3c789d
--- /dev/null
+++ b/lib/lib_display/UDisplay/uDisplay.h
@@ -0,0 +1,114 @@
+#ifndef _UDISP_
+#define _UDISP_
+
+#include
+#include
+
+#define _UDSP_I2C 1
+#define _UDSP_SPI 2
+
+#define UDISP1_WHITE 1
+#define UDISP1_BLACK 0
+
+
+// Color definitions
+#define UDISP_BLACK 0x0000 /* 0, 0, 0 */
+#define UDISP_NAVY 0x000F /* 0, 0, 128 */
+#define UDISP_DARKGREEN 0x03E0 /* 0, 128, 0 */
+#define UDISP_DARKCYAN 0x03EF /* 0, 128, 128 */
+#define UDISP_MAROON 0x7800 /* 128, 0, 0 */
+#define UDISP_PURPLE 0x780F /* 128, 0, 128 */
+#define UDISP_OLIVE 0x7BE0 /* 128, 128, 0 */
+#define UDISP_LIGHTGREY 0xC618 /* 192, 192, 192 */
+#define UDISP_DARKGREY 0x7BEF /* 128, 128, 128 */
+#define UDISP_BLUE 0x001F /* 0, 0, 255 */
+#define UDISP_GREEN 0x07E0 /* 0, 255, 0 */
+#define UDISP_CYAN 0x07FF /* 0, 255, 255 */
+#define UDISP_RED 0xF800 /* 255, 0, 0 */
+#define UDISP_MAGENTA 0xF81F /* 255, 0, 255 */
+#define UDISP_YELLOW 0xFFE0 /* 255, 255, 0 */
+#define UDISP_WHITE 0xFFFF /* 255, 255, 255 */
+#define UDISP_ORANGE 0xFD20 /* 255, 165, 0 */
+#define UDISP_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
+#define UDISP_PINK 0xF81F
+
+#define SPI_BEGIN_TRANSACTION uspi->beginTransaction(spiSettings);
+#define SPI_END_TRANSACTION uspi->endTransaction();
+#define SPI_CS_LOW if (spi_cs >= 0) digitalWrite(spi_cs, LOW);
+#define SPI_CS_HIGH if (spi_cs >= 0) digitalWrite(spi_cs, HIGH);
+#define SPI_DC_LOW if (spi_dc >= 0) digitalWrite(spi_dc, LOW);
+#define SPI_DC_HIGH if (spi_dc >= 0) digitalWrite(spi_dc, HIGH);
+
+#define ESP32_PWM_CHANNEL 1
+
+class uDisplay : public Renderer {
+ public:
+ uDisplay(char *);
+ Renderer *Init(void);
+ void DisplayInit(int8_t p,int8_t size,int8_t rot,int8_t font);
+ void Updateframe();
+ void DisplayOnff(int8_t on);
+ void Splash(void);
+ char *devname(void);
+ uint16_t fgcol(void) const { return fg_col; };
+ uint16_t bgcol(void) const { return bg_col; };
+ void dim(uint8_t dim);
+ uint16_t GetColorFromIndex(uint8_t index);
+ void setRotation(uint8_t m);
+ void fillScreen(uint16_t color);
+ void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
+ void pushColors(uint16_t *data, uint16_t len, boolean first);
+
+ private:
+ void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
+ void drawPixel(int16_t x, int16_t y, uint16_t color);
+ void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color);
+ void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color);
+ uint32_t str2c(char **sp, char *vp, uint32_t len);
+ void i2c_command(uint8_t val);
+ void spi_command(uint8_t val);
+ uint8_t strlen_ln(char *str);
+ int32_t next_val(char **sp);
+ uint32_t next_hex(char **sp);
+ void setAddrWindow_int(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
+ char dname[16];
+ int8_t bpp;
+ uint8_t interface;
+ uint8_t i2caddr;
+ int8_t i2c_scl;
+ int8_t i2c_sda;
+ int8_t reset;
+ uint8_t dsp_cmds[128];
+ uint8_t dsp_ncmds;
+ uint8_t dsp_on;
+ uint8_t dsp_off;
+ uint16_t splash_font;
+ uint16_t splash_size;
+ uint16_t splash_xp;
+ uint16_t splash_yp;
+ uint16_t fg_col;
+ uint16_t bg_col;
+ uint16_t gxs;
+ uint16_t gys;
+ int8_t spi_cs;
+ int8_t spi_clk;
+ int8_t spi_mosi;
+ int8_t spi_dc;
+ int8_t bpanel;
+ int8_t spi_miso;
+ uint8_t dimmer;
+ SPIClass *uspi;
+ SPISettings spiSettings;
+ uint32_t spi_speed;
+ uint8_t spi_nr = 1;
+ uint8_t rot_0;
+ uint8_t rot_1;
+ uint8_t rot_2;
+ uint8_t rot_3;
+ uint8_t saw_1;
+ uint8_t saw_2;
+ uint8_t saw_3;
+ uint8_t flags;
+};
+
+#endif // _UDISP_
diff --git a/tasmota/displaydesc/ILI9341_desc.txt b/tasmota/displaydesc/ILI9341_desc.txt
new file mode 100644
index 000000000..6aab1b1c5
--- /dev/null
+++ b/tasmota/displaydesc/ILI9341_desc.txt
@@ -0,0 +1,50 @@
+; name,xs,ys,bpp,interface, spi_nr cs, sclk,mosi,dc, bp ,reset,miso,spi_speed
+:H
+ILI9341,240,320,16,SPI,1,*,*,*,*,*,*,*,40000000
+; splash settings, font, size, fgcol, bgcol, x,y
+:S
+2,1,1,0,40,20
+; initialyze
+:I
+EF,3,03,80,02
+CF,3,00,C1,30
+ED,4,64,03,12,81
+E8,3,85,00,78
+CB,5,39,2C,00,34,02
+F7,1,20
+EA,2,00,00
+C0,1,23
+C1,1,10
+C5,2,3e,28
+C7,1,86
+36,1,48
+37,1,00
+3A,1,55
+B1,2,00,18
+B6,3,08,82,27
+F2,1,00
+26,1,01
+E0,0F,0F,31,2B,0C,0E,08,4E,F1,37,07,10,03,0E,09,00
+E1,0F,00,0E,14,03,11,07,31,C1,48,08,0F,0C,31,36,0F
+11,80
+29,80
+; off
+:o
+28
+; on
+:O
+29
+; set adress window
+:A
+2A,2B,2C
+; rotation
+:0
+48
+:1
+28
+:2
+88
+:3
+E8
+#
+
diff --git a/tasmota/displaydesc/SH1106_desc.txt b/tasmota/displaydesc/SH1106_desc.txt
new file mode 100644
index 000000000..954cb3740
--- /dev/null
+++ b/tasmota/displaydesc/SH1106_desc.txt
@@ -0,0 +1,31 @@
+; name,xs,ys,bpp,interface, address, scl,sda,reset
+:H
+SH1106,128,64,1,I2C,3c,*,*,*
+; splash settings, font, size, fgcol, bgcol, x,y
+:S
+0,1,1,0,40,20
+; init register settings
+:I
+AE
+D5,80
+A8,3f
+D3,00
+40
+8D,14
+20,00
+A1
+C8
+DA,12
+81,CF
+D9F1
+DB,40
+A4
+A6
+AF
+; switch display off
+:o
+AE
+; switch display on
+:O
+AF
+#
\ No newline at end of file
diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h
index 70bcff270..9b27c12d9 100644
--- a/tasmota/tasmota_template.h
+++ b/tasmota/tasmota_template.h
@@ -169,14 +169,14 @@ enum ProgramSelectablePins {
GPIO_USER, // User configurable needs to be 2047
GPIO_MAX };
-#define MAX_OPTIONS_A 2 // Increase if more bits are used from GpioOptionABits
+#define MAX_OPTIONS_A 3 // Increase if more bits are used from GpioOptionABits
typedef union { // Restricted by MISRA-C Rule 18.4 but so useful...
uint32_t data; // Allow bit manipulation using SetOption
struct { // GPIO Option_A1 .. Option_A32
uint32_t pwm1_input : 1; // bit 0 (v9.2.0.1) - Option_A1 - (Light) Change PWM1 to input on power off and no fade running (1)
uint32_t dummy_energy : 1; // bit 1 (v9.3.1.2) - Option_A2 - (Energy) Enable dummy values
- uint32_t spare02 : 1; // bit 2
+ uint32_t udisplay_driver : 1; // bit 2 Universal display driver
uint32_t spare03 : 1; // bit 3
uint32_t spare04 : 1; // bit 4
uint32_t spare05 : 1; // bit 5
diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino
index 7731237bd..5e920afba 100755
--- a/tasmota/xdrv_10_scripter.ino
+++ b/tasmota/xdrv_10_scripter.ino
@@ -65,7 +65,9 @@ keywords if then else endif, or, and are better readable for beginners (others m
#define SCRIPT_MAXPERM (PMEM_SIZE)-4/sizeof(float)
#define MAX_SCRIPT_SIZE MAX_RULE_SIZE*MAX_RULE_SETS
+#ifndef MAX_SARRAY_NUM
#define MAX_SARRAY_NUM 32
+#endif
uint32_t EncodeLightId(uint8_t relay_id);
uint32_t DecodeLightId(uint32_t hue_id);
@@ -1413,38 +1415,42 @@ uint32_t match_vars(char *dvnam, float **fp, char **sp, uint32_t *ind) {
}
#endif //USE_SCRIPT_GLOBVARS
+#ifndef SCRIPT_IS_STRING_MAXSIZE
+#define SCRIPT_IS_STRING_MAXSIZE 256
+#endif
+
char *isargs(char *lp, uint32_t isind) {
float fvar;
lp = GetNumericArgument(lp, OPER_EQU, &fvar, 0);
SCRIPT_SKIP_SPACES
- if (*lp!='"') {
+ if (*lp != '"') {
return lp;
}
lp++;
- if (glob_script_mem.si_num[isind]>0 && glob_script_mem.last_index_string[isind]) {
+ if (glob_script_mem.si_num[isind] > 0 && glob_script_mem.last_index_string[isind]) {
free(glob_script_mem.last_index_string[isind]);
}
char *sstart = lp;
uint8_t slen = 0;
- for (uint32_t cnt = 0; cnt<256; cnt++) {
- if (*lp=='\n' || *lp=='"' || *lp==0) {
+ for (uint32_t cnt = 0; cnt < SCRIPT_IS_STRING_MAXSIZE; cnt++) {
+ if (*lp == '\n' || *lp == '"' || *lp == 0) {
lp++;
- if (cnt>0 && !slen) {
+ if (cnt > 0 && !slen) {
slen++;
}
glob_script_mem.siro_num[isind] = slen;
break;
}
- if (*lp=='|') {
+ if (*lp == '|') {
slen++;
}
lp++;
}
glob_script_mem.si_num[isind] = fvar;
- if (glob_script_mem.si_num[isind]>0) {
- if (glob_script_mem.si_num[isind]>MAX_SARRAY_NUM) {
+ if (glob_script_mem.si_num[isind] > 0) {
+ if (glob_script_mem.si_num[isind] > MAX_SARRAY_NUM) {
glob_script_mem.si_num[isind] = MAX_SARRAY_NUM;
}
@@ -1468,17 +1474,17 @@ float fvar;
char str[SCRIPT_MAXSSIZE];
str[0] = 0;
uint8_t index = fvar;
- if (index<1) index = 1;
+ if (index < 1) index = 1;
index--;
if (gv) gv->strind = index;
glob_script_mem.sind_num = isind;
if (glob_script_mem.last_index_string[isind]) {
if (!glob_script_mem.si_num[isind]) {
- if (index<=glob_script_mem.siro_num[isind]) {
+ if (index <= glob_script_mem.siro_num[isind]) {
GetTextIndexed(str, sizeof(str), index , glob_script_mem.last_index_string[isind]);
}
} else {
- if (index>glob_script_mem.si_num[isind]) {
+ if (index > glob_script_mem.si_num[isind]) {
index = glob_script_mem.si_num[isind];
}
strlcpy(str,glob_script_mem.last_index_string[isind] + (index * glob_script_mem.max_ssize), glob_script_mem.max_ssize);
@@ -1866,6 +1872,15 @@ chknext:
}
#endif //USE_SCRIPT_TASK
#endif //ESP32
+#ifdef USE_ANGLE_FUNC
+ if (!strncmp(vname, "cos(", 4)) {
+ lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv);
+ fvar = cosf(fvar);
+ lp++;
+ len = 0;
+ goto exit;
+ }
+#endif
break;
case 'd':
if (!strncmp(vname, "day", 3)) {
@@ -2196,6 +2211,22 @@ chknext:
len = 0;
goto exit;
}
+ if (!strncmp(vname, "fmt(", 4)) {
+ lp = GetNumericArgument(lp + 4, OPER_EQU, &fvar, gv);
+ if (!fvar) {
+#ifdef ESP8266
+ LittleFS.format();
+#endif
+#ifdef ESP32
+ LITTLEFS.format();
+#endif
+ } else {
+ //SD.format();
+ }
+ lp++;
+ len = 0;
+ goto exit;
+ }
if (!strncmp(vname, "frd(", 4)) {
char str[glob_script_mem.max_ssize + 1];
lp = GetStringArgument(lp + 4, OPER_EQU, str, 0);
diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino
index fe599d7a7..1b8a19df9 100755
--- a/tasmota/xdrv_13_display.ino
+++ b/tasmota/xdrv_13_display.ino
@@ -80,6 +80,7 @@ const uint8_t DISPLAY_LOG_ROWS = 32; // Number of lines in display log
#define D_CMND_DISP_CLOCK "Clock"
#define D_CMND_DISP_TEXTNC "TextNC" // NC - "No Clear"
#define D_CMND_DISP_SCROLLTEXT "ScrollText"
+#define D_CMND_DISP_REINIT "reinit"
enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER, FUNC_DISPLAY_INIT, FUNC_DISPLAY_EVERY_50_MSECOND, FUNC_DISPLAY_EVERY_SECOND,
FUNC_DISPLAY_MODEL, FUNC_DISPLAY_MODE, FUNC_DISPLAY_POWER,
@@ -108,7 +109,7 @@ const char kDisplayCommands[] PROGMEM = D_PRFX_DISPLAY "|" // Prefix
#endif
D_CMND_DISP_CLEAR "|" D_CMND_DISP_NUMBER "|" D_CMND_DISP_FLOAT "|" D_CMND_DISP_NUMBERNC "|" D_CMND_DISP_FLOATNC "|"
D_CMND_DISP_RAW "|" D_CMND_DISP_LEVEL "|" D_CMND_DISP_SEVENSEG_TEXT "|" D_CMND_DISP_SEVENSEG_TEXTNC "|"
- D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" D_CMND_DISP_SCROLLTEXT
+ D_CMND_DISP_SCROLLDELAY "|" D_CMND_DISP_CLOCK "|" D_CMND_DISP_TEXTNC "|" D_CMND_DISP_SCROLLTEXT "|" D_CMND_DISP_REINIT
;
void (* const DisplayCommand[])(void) PROGMEM = {
@@ -120,7 +121,7 @@ void (* const DisplayCommand[])(void) PROGMEM = {
#endif
&CmndDisplayClear, &CmndDisplayNumber, &CmndDisplayFloat, &CmndDisplayNumberNC, &CmndDisplayFloatNC,
&CmndDisplayRaw, &CmndDisplayLevel, &CmndDisplaySevensegText, &CmndDisplaySevensegTextNC,
- &CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, &CmndDisplayScrollText
+ &CmndDisplayScrollDelay, &CmndDisplayClock, &CmndDisplayTextNC, &CmndDisplayScrollText,&DisplayReInitDriver
};
#ifdef USE_GRAPH
@@ -989,7 +990,7 @@ void Display_Text_From_File(const char *file) {
File fp;
if (!ufsp) return;
fp = ufsp->open(file, FS_FILE_READ);
- if (fp >= 0) {
+ if (fp > 0) {
char *savptr = XdrvMailbox.data;
char linebuff[128];
while (fp.available()) {
@@ -1021,7 +1022,7 @@ void Display_Text_From_File(const char *file) {
fp.close();
}
}
-#endif
+#endif // USE_UFILESYS
#ifdef USE_DT_VARS
@@ -2001,6 +2002,11 @@ void CmndDisplayScrollText(void) {
if(result) ResponseCmndChar(XdrvMailbox.data);
}
+void DisplayReInitDriver(void) {
+ XdspCall(FUNC_DISPLAY_INIT_DRIVER);
+ ResponseCmndDone();
+}
+
/*********************************************************************************************\
* Optional drivers
\*********************************************************************************************/
diff --git a/tasmota/xdsp_17_universal.ino b/tasmota/xdsp_17_universal.ino
new file mode 100644
index 000000000..c72b4cb85
--- /dev/null
+++ b/tasmota/xdsp_17_universal.ino
@@ -0,0 +1,332 @@
+/*
+ xdsp_17_universal.ino - universal display driver support for Tasmota
+
+ Copyright (C) 2021 Gerhard Mutz and Theo Arends
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+
+#ifdef USE_DISPLAY
+#ifdef USE_UNIVERSAL_DISPLAY
+
+#define XDSP_17 17
+
+#include
+
+uDisplay *udisp;
+bool udisp_init_done = false;
+extern uint8_t color_type;
+extern uint16_t fg_color;
+extern uint16_t bg_color;
+
+#ifdef USE_UFILESYS
+extern FS *ufsp;
+#endif
+
+#define DISPDESC_SIZE 1000
+
+#define DSP_ROM_DESC
+
+/*********************************************************************************************/
+#ifdef DSP_ROM_DESC
+/* sample descriptor */
+const char DSP_SAMPLE_DESC[] PROGMEM =
+// name,xs,ys,bpp,interface, (HEX) address, scl,sda,reset
+// '*' means take pin number from tasmota
+":H\n"
+"SH1106,128,64,1,I2C,3c,*,*,*\n"
+// splash settings, font, size, fgcol, bgcol, x,y
+":S\n"
+"0,1,1,0,40,20\n"
+// init register settings, must be in HEX
+":I\n"
+"AE\n"
+"D5,80\n"
+"A8,3f\n"
+"D3,00\n"
+"40\n"
+"8D,14\n"
+"20,00\n"
+"A1\n"
+"C8\n"
+"DA,12\n"
+"81,CF\n"
+"D9F1\n"
+"DB,40\n"
+"A4\n"
+"A6\n"
+"AF\n"
+// switch display off
+":o\n"
+"AE\n"
+// switch display on
+":O\n"
+"AF\n"
+"#\n";
+
+#endif // DSP_ROM_DESC
+/*********************************************************************************************/
+
+void Init_uDisp(void) {
+char *ddesc = 0;
+char *fbuff;
+
+ if (TasmotaGlobal.gpio_optiona.udisplay_driver) {
+ Settings.display_model = XDSP_17;
+
+ fg_color = 1;
+ bg_color = 0;
+ color_type = COLOR_BW;
+
+ fbuff = (char*)calloc(DISPDESC_SIZE, 1);
+ if (!fbuff) return;
+
+#ifdef USE_UFILESYS
+ if (ufsp && !TasmotaGlobal.no_autoexec) {
+ File fp;
+ fp = ufsp->open("/dispdesc.txt", "r");
+ if (fp > 0) {
+ uint32_t size = fp.size();
+ fp.read((uint8_t*)fbuff, size);
+ fp.close();
+ ddesc = fbuff;
+ AddLog(LOG_LEVEL_INFO, PSTR("DSP: File descriptor used"));
+ }
+ }
+#endif
+
+
+#ifdef USE_SCRIPT
+ if (bitRead(Settings.rule_enabled, 0) && !ddesc) {
+ uint8_t dfound = Run_Scripter(">d",-2,0);
+ if (dfound == 99) {
+ char *lp = glob_script_mem.section_ptr + 2;
+ while (*lp != '\n') lp++;
+ memcpy(fbuff, lp + 1, DISPDESC_SIZE - 1);
+ ddesc = fbuff;
+ AddLog(LOG_LEVEL_INFO, PSTR("DSP: Script descriptor used"));
+ }
+ }
+#endif // USE_SCRIPT
+
+
+#ifdef DSP_ROM_DESC
+ if (!ddesc) {
+ memcpy_P(fbuff, DSP_SAMPLE_DESC, sizeof(DSP_SAMPLE_DESC));
+ ddesc = fbuff;
+ AddLog(LOG_LEVEL_INFO, PSTR("DSP: Flash descriptor used"));
+ }
+#endif // DSP_ROM_DESC
+
+ if (!ddesc) {
+ AddLog(LOG_LEVEL_INFO, PSTR("DSP: No valid descriptor found"));
+ if (fbuff) free(fbuff);
+ return;
+ }
+ // now replace tasmota vars before passing to driver
+ char *cp = strstr(ddesc, "I2C");
+ if (cp) {
+ cp += 4;
+ //,3c,22,21,-1
+ // i2c addr
+ //if (*cp == '*') {
+ // Settings.display_address
+ //}
+ uint8_t i2caddr = strtol(cp, 0, 16);
+ if (I2cSetDevice(i2caddr)) {
+ I2cSetActiveFound(i2caddr, "DSP-I2C");
+ }
+ cp+=3;
+ //replacepin(&cp, Settings.display_address);
+ replacepin(&cp, Pin(GPIO_I2C_SCL));
+ replacepin(&cp, Pin(GPIO_I2C_SDA));
+ replacepin(&cp, Pin(GPIO_OLED_RESET));
+ }
+
+ cp = strstr(ddesc, "SPI");
+ if (cp) {
+ cp += 4;
+ //; 7 params nr,cs,sclk,mosi,dc,bl,reset,miso
+ //SPI,*,*,*,*,*,*,*
+ if (*cp == '1') {
+ cp+=2;
+ replacepin(&cp, Pin(GPIO_SPI_CS));
+ replacepin(&cp, Pin(GPIO_SPI_CLK));
+ replacepin(&cp, Pin(GPIO_SPI_MOSI));
+ replacepin(&cp, Pin(GPIO_SPI_DC));
+ replacepin(&cp, Pin(GPIO_BACKLIGHT));
+ replacepin(&cp, Pin(GPIO_OLED_RESET));
+ replacepin(&cp, Pin(GPIO_SPI_MISO));
+ } else {
+ // soft spi pins
+ cp+=2;
+ replacepin(&cp, Pin(GPIO_SSPI_CS));
+ replacepin(&cp, Pin(GPIO_SSPI_SCLK));
+ replacepin(&cp, Pin(GPIO_SSPI_MOSI));
+ replacepin(&cp, Pin(GPIO_SSPI_DC));
+ replacepin(&cp, Pin(GPIO_BACKLIGHT));
+ replacepin(&cp, Pin(GPIO_OLED_RESET));
+ replacepin(&cp, Pin(GPIO_SSPI_MISO));
+ }
+ }
+
+ // init renderer
+ if (udisp) delete udisp;
+ udisp = new uDisplay(ddesc);
+
+/*
+ File fp;
+ fp = ufsp->open("/dump.txt", "w");
+ fp.write(ddesc, DISPDESC_SIZE);
+ fp.close();
+*/
+ // release desc buffer
+ if (fbuff) free(fbuff);
+
+ renderer = udisp->Init();
+ if (!renderer) return;
+
+ Settings.display_width = renderer->width();
+ Settings.display_height = renderer->height();
+ fg_color = udisp->fgcol();
+ bg_color = udisp->bgcol();
+
+ renderer->DisplayInit(DISPLAY_INIT_MODE, Settings.display_size, Settings.display_rotate, Settings.display_font);
+
+
+#ifdef SHOW_SPLASH
+ udisp->Splash();
+#endif
+
+ udisp_init_done = true;
+ AddLog(LOG_LEVEL_INFO, PSTR("DSP: %s!"), udisp->devname());
+ }
+}
+
+
+/*********************************************************************************************/
+
+void replacepin(char **cp, uint16_t pin) {
+ char *lp = *cp;
+ if (*lp == ',') lp++;
+ if (*lp == '*') {
+ char val[8];
+ itoa(pin, val, 10);
+ uint16_t slen = strlen(val);
+ //AddLog(LOG_LEVEL_INFO, PSTR("replace pin: %d"), pin);
+ memmove(lp + slen, lp + 1, strlen(lp));
+ memmove(lp, val, slen);
+ }
+ char *np = strchr(lp, ',');
+ if (np) {
+ *cp = np + 1;
+ }
+}
+
+#ifdef USE_DISPLAY_MODES1TO5
+
+void UDISP_PrintLog(void)
+{
+ disp_refresh--;
+ if (!disp_refresh) {
+ disp_refresh = Settings.display_refresh;
+ if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); }
+
+ char* txt = DisplayLogBuffer('\370');
+ if (txt != NULL) {
+ uint8_t last_row = Settings.display_rows -1;
+
+ renderer->clearDisplay();
+ renderer->setTextSize(Settings.display_size);
+ renderer->setCursor(0,0);
+ for (byte i = 0; i < last_row; i++) {
+ strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols);
+ renderer->println(disp_screen_buffer[i]);
+ }
+ strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols);
+ DisplayFillScreen(last_row);
+
+ AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]);
+
+ renderer->println(disp_screen_buffer[last_row]);
+ renderer->Updateframe();
+ }
+ }
+}
+
+void UDISP_Time(void)
+{
+ char line[12];
+
+ renderer->clearDisplay();
+ renderer->setTextSize(Settings.display_size);
+ renderer->setTextFont(Settings.display_font);
+ renderer->setCursor(0, 0);
+ snprintf_P(line, sizeof(line), PSTR(" %02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second); // [ 12:34:56 ]
+ renderer->println(line);
+ renderer->println();
+ snprintf_P(line, sizeof(line), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year); // [01-02-2018]
+ renderer->println(line);
+ renderer->Updateframe();
+}
+
+void UDISP_Refresh(void) // Every second
+{
+ if (!renderer) return;
+ if (Settings.display_mode) { // Mode 0 is User text
+ switch (Settings.display_mode) {
+ case 1: // Time
+ UDISP_Time();
+ break;
+ case 2: // Local
+ case 3: // Local
+ case 4: // Mqtt
+ case 5: // Mqtt
+ UDISP_PrintLog();
+ break;
+ }
+ }
+}
+
+#endif // USE_DISPLAY_MODES1TO5
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xdsp17(uint8_t function)
+{
+ bool result = false;
+
+ if (FUNC_DISPLAY_INIT_DRIVER == function) {
+ Init_uDisp();
+ }
+ else if (udisp_init_done && (XDSP_17 == Settings.display_model)) {
+ switch (function) {
+ case FUNC_DISPLAY_MODEL:
+ result = true;
+ break;
+#ifdef USE_DISPLAY_MODES1TO5
+ case FUNC_DISPLAY_EVERY_SECOND:
+ UDISP_Refresh();
+ break;
+#endif // USE_DISPLAY_MODES1TO5
+ }
+ }
+ return result;
+}
+
+#endif // USE_UNIVERSAL_DISPLAY
+#endif // USE_DISPLAY