Update display drivers

Add features to and provide more stable display drivers
This commit is contained in:
Theo Arends 2018-08-31 12:17:09 +02:00
parent 67db78b759
commit fb6640e94b
6 changed files with 172 additions and 194 deletions

View File

@ -1,5 +1,6 @@
/* 6.1.1.14 20180830
* Add boot loop detection and perform some solutions
* Add features to and provide more stable display drivers
*
* 6.1.1.13 20180828
* Fix 6.1.1.12 regression of Mem and Var default handling (#3618)

View File

@ -89,7 +89,6 @@ char **disp_log_buffer;
uint8_t disp_log_buffer_cols = 0;
uint8_t disp_log_buffer_idx = 0;
uint8_t disp_log_buffer_ptr = 0;
bool disp_log_buffer_active = false;
char **disp_screen_buffer;
uint8_t disp_screen_buffer_cols = 0;
@ -534,6 +533,15 @@ void DisplayReAllocScreenBuffer()
DisplayAllocScreenBuffer();
}
void DisplayFillScreen(uint8_t line)
{
byte len = disp_screen_buffer_cols - strlen(disp_screen_buffer[line]);
if (len) {
memset(disp_screen_buffer[line] + strlen(disp_screen_buffer[line]), 0x20, len);
disp_screen_buffer[line][disp_screen_buffer_cols -1] = 0;
}
}
/*-------------------------------------------------------------------------------------------*/
void DisplayClearLogBuffer()
@ -582,55 +590,47 @@ void DisplayReAllocLogBuffer()
DisplayAllocLogBuffer();
}
/*-------------------------------------------------------------------------------------------*/
void DisplayLogBufferIdxInc()
void DisplayLogBufferAdd(char* txt)
{
disp_log_buffer_idx++;
if (DISPLAY_LOG_ROWS == disp_log_buffer_idx) {
disp_log_buffer_idx = 0;
if (disp_log_buffer_cols) {
strlcpy(disp_log_buffer[disp_log_buffer_idx], txt, disp_log_buffer_cols); // This preserves the % sign where printf won't
disp_log_buffer_idx++;
if (DISPLAY_LOG_ROWS == disp_log_buffer_idx) { disp_log_buffer_idx = 0; }
}
}
void DisplayLogBufferPtrInc()
char* DisplayLogBuffer(char temp_code)
{
disp_log_buffer_ptr++;
if (DISPLAY_LOG_ROWS == disp_log_buffer_ptr) {
disp_log_buffer_ptr = 0;
}
}
char* result = NULL;
if (disp_log_buffer_cols) {
if (disp_log_buffer_idx != disp_log_buffer_ptr) {
result = disp_log_buffer[disp_log_buffer_ptr];
disp_log_buffer_ptr++;
if (DISPLAY_LOG_ROWS == disp_log_buffer_ptr) { disp_log_buffer_ptr = 0; }
/*
void DisplayPrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
XdspPrintLog(disp_log_buffer[disp_log_buffer_ptr]);
DisplayLogBufferPtrInc();
char *pch = strchr(result, '~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) { result[pch - result] = temp_code; }
}
}
return result;
}
*/
void DisplayLogBufferInit()
{
if (Settings.display_mode) {
disp_log_buffer_idx = 0;
disp_log_buffer_ptr = 0;
disp_log_buffer_active = false;
disp_refresh = Settings.display_refresh;
snprintf_P(disp_temp, sizeof(disp_temp), PSTR("%c"), TempUnit());
// DisplayReAllocLogBuffer();
DisplayReAllocLogBuffer();
snprintf_P(disp_log_buffer[disp_log_buffer_idx], disp_log_buffer_cols, PSTR(D_VERSION " %s"), my_version);
DisplayLogBufferIdxInc();
snprintf_P(disp_log_buffer[disp_log_buffer_idx], disp_log_buffer_cols, PSTR("Display mode %d"), Settings.display_mode);
DisplayLogBufferIdxInc();
char buffer[20];
snprintf_P(buffer, sizeof(buffer), PSTR(D_VERSION " %s"), my_version);
DisplayLogBufferAdd(buffer);
snprintf_P(buffer, sizeof(buffer), PSTR("Display mode %d"), Settings.display_mode);
DisplayLogBufferAdd(buffer);
}
}
@ -668,6 +668,7 @@ const char kSensorQuantity[] PROGMEM =
void DisplayJsonValue(const char *topic, const char* device, const char* mkey, const char* value)
{
char quantity[TOPSZ];
char buffer[Settings.display_cols[0] +1];
char spaces[Settings.display_cols[0]];
char source[Settings.display_cols[0] - Settings.display_cols[1]];
char svalue[Settings.display_cols[1] +1];
@ -718,12 +719,12 @@ void DisplayJsonValue(const char *topic, const char* device, const char* mkey, c
else if (JSON_CO2 == quantity_code) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s" D_UNIT_PARTS_PER_MILLION), value);
}
snprintf_P(disp_log_buffer[disp_log_buffer_idx], disp_log_buffer_cols, PSTR("%s %s"), source, svalue);
snprintf_P(buffer, sizeof(buffer), PSTR("%s %s"), source, svalue);
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "mkey [%s], source [%s], value [%s], quantity_code %d, log_buffer [%s]"), mkey, source, value, quantity_code, disp_log_buffer[disp_log_buffer_idx]);
// snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "mkey [%s], source [%s], value [%s], quantity_code %d, log_buffer [%s]"), mkey, source, value, quantity_code, buffer);
// AddLog(LOG_LEVEL_DEBUG);
DisplayLogBufferIdxInc();
DisplayLogBufferAdd(buffer);
}
void DisplayAnalyzeJson(char *topic, char *json)
@ -856,7 +857,6 @@ void DisplayInitDriver()
#ifndef USE_DISPLAY_MODES1TO5
Settings.display_mode = 0;
#else
DisplayAllocLogBuffer();
DisplayLogBufferInit();
#endif // USE_DISPLAY_MODES1TO5
}
@ -981,8 +981,7 @@ boolean DisplayCommand()
if (!Settings.display_mode) {
DisplayText();
} else {
strlcpy(disp_log_buffer[disp_log_buffer_idx], XdrvMailbox.data, disp_log_buffer_cols);
DisplayLogBufferIdxInc();
DisplayLogBufferAdd(XdrvMailbox.data);
}
#endif // USE_DISPLAY_MODES1TO5
} else {
@ -1006,22 +1005,23 @@ boolean DisplayCommand()
}
else if ((CMND_DISP_COLS == command_code) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 2)) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_COLS)) {
Settings.display_cols[XdrvMailbox.index -1] = XdrvMailbox.payload;
#ifdef USE_DISPLAY_MODES1TO5
if ((1 == XdrvMailbox.index) && (Settings.display_cols[0] != XdrvMailbox.payload)) {
if (1 == XdrvMailbox.index) {
DisplayLogBufferInit();
DisplayReAllocScreenBuffer();
}
#endif // USE_DISPLAY_MODES1TO5
Settings.display_cols[XdrvMailbox.index -1] = XdrvMailbox.payload;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_INDEX_NVALUE, command, XdrvMailbox.index, Settings.display_cols[XdrvMailbox.index -1]);
}
else if (CMND_DISP_ROWS == command_code) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= DISPLAY_MAX_ROWS)) {
#ifdef USE_DISPLAY_MODES1TO5
if (Settings.display_rows != XdrvMailbox.payload) { DisplayReAllocScreenBuffer(); }
#endif // USE_DISPLAY_MODES1TO5
Settings.display_rows = XdrvMailbox.payload;
#ifdef USE_DISPLAY_MODES1TO5
DisplayLogBufferInit();
DisplayReAllocScreenBuffer();
#endif // USE_DISPLAY_MODES1TO5
}
snprintf_P(mqtt_data, sizeof(mqtt_data), S_JSON_DISPLAY_COMMAND_NVALUE, command, Settings.display_rows);
}

View File

@ -112,51 +112,37 @@ void LcdCenter(byte row, char* txt)
lcd->print(line);
}
void LcdPrintLogLine()
boolean LcdPrintLog()
{
if (!disp_screen_buffer_cols) {
DisplayAllocScreenBuffer();
} else {
uint8_t last_row = Settings.display_rows -1;
boolean result = false;
for (byte i = 0; i < last_row; i++) {
strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols);
lcd->setCursor(0, i); // Col 0, Row i
lcd->print(disp_screen_buffer[i +1]);
}
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\337'; // = 0xDF
}
strlcpy(disp_screen_buffer[last_row], disp_log_buffer[disp_log_buffer_ptr], disp_screen_buffer_cols);
// Fill with spaces
byte len = disp_screen_buffer_cols - strlen(disp_screen_buffer[last_row]);
if (len) {
memset(disp_screen_buffer[last_row] + strlen(disp_screen_buffer[last_row]), 0x20, len);
disp_screen_buffer[last_row][disp_screen_buffer_cols -1] = 0;
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]);
AddLog(LOG_LEVEL_DEBUG);
lcd->setCursor(0, last_row);
lcd->print(disp_screen_buffer[last_row]);
}
}
void LcdPrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
LcdPrintLogLine();
DisplayLogBufferPtrInc();
if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); }
char* txt = DisplayLogBuffer('\337');
if (txt != NULL) {
uint8_t last_row = Settings.display_rows -1;
for (byte i = 0; i < last_row; i++) {
strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols);
lcd->setCursor(0, i); // Col 0, Row i
lcd->print(disp_screen_buffer[i +1]);
}
strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols);
DisplayFillScreen(last_row);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]);
AddLog(LOG_LEVEL_DEBUG);
lcd->setCursor(0, last_row);
lcd->print(disp_screen_buffer[last_row]);
result = true;
}
}
return result;
}
void LcdTime()
@ -182,10 +168,7 @@ void LcdRefresh() // Every second
break;
case 3: // Local
case 5: { // Mqtt
LcdPrintLog();
if (!disp_log_buffer_active) {
LcdTime();
}
if (!LcdPrintLog()) { LcdTime(); }
break;
}
}

View File

@ -133,52 +133,32 @@ void Ssd1306OnOff()
#ifdef USE_DISPLAY_MODES1TO5
void Ssd1306PrintLogLine()
{
if (!disp_screen_buffer_cols) {
DisplayAllocScreenBuffer();
} else {
uint8_t last_row = Settings.display_rows -1;
oled->clearDisplay();
oled->setTextSize(Settings.display_size);
oled->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);
oled->println(disp_screen_buffer[i]);
}
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\370'; // = 0xF8
}
strlcpy(disp_screen_buffer[last_row], disp_log_buffer[disp_log_buffer_ptr], disp_screen_buffer_cols);
// Fill with spaces
byte len = disp_screen_buffer_cols - strlen(disp_screen_buffer[last_row]);
if (len) {
memset(disp_screen_buffer[last_row] + strlen(disp_screen_buffer[last_row]), 0x20, len);
disp_screen_buffer[last_row][disp_screen_buffer_cols -1] = 0;
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]);
AddLog(LOG_LEVEL_DEBUG);
oled->println(disp_screen_buffer[last_row]);
oled->display();
}
}
void Ssd1306PrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
Ssd1306PrintLogLine();
DisplayLogBufferPtrInc();
if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); }
char* txt = DisplayLogBuffer('\370');
if (txt != NULL) {
uint8_t last_row = Settings.display_rows -1;
oled->clearDisplay();
oled->setTextSize(Settings.display_size);
oled->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);
oled->println(disp_screen_buffer[i]);
}
strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols);
DisplayFillScreen(last_row);
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_DEBUG "[%s]"), disp_screen_buffer[last_row]);
AddLog(LOG_LEVEL_DEBUG);
oled->println(disp_screen_buffer[last_row]);
oled->display();
}
}
}

View File

@ -39,6 +39,7 @@ int16_t mtx_y = 0;
char mtx_buffer[MTX_MAX_SCREEN_BUFFER];
uint8_t mtx_mode = 0;
uint8_t mtx_loop = 0;
uint8_t mtx_done = 0;
/*********************************************************************************************/
@ -109,9 +110,7 @@ void MatrixScrollLeft(char* txt, int loop)
// Move text position left by 1 pixel.
mtx_x--;
int16_t len = strlen(txt);
if (mtx_x < -(len *6)) {
mtx_state = loop;
}
if (mtx_x < -(len *6)) { mtx_state = loop; }
}
break;
}
@ -159,9 +158,7 @@ void MatrixScrollUp(char* txt, int loop)
mtx_y--; // Move text position up by 1 pixel.
mtx_counter = STATES * 1; // Hold text for 1 seconds
}
if (mtx_y < -(wordcounter *8)) {
mtx_state = loop;
}
if (mtx_y < -(wordcounter *8)) { mtx_state = loop; }
}
break;
}
@ -220,16 +217,14 @@ void MatrixInitDriver()
void MatrixOnOff()
{
if (!disp_power) {
MatrixClear();
}
if (!disp_power) { MatrixClear(); }
}
void MatrixDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8_t flag)
{
snprintf(mtx_buffer, sizeof(mtx_buffer), str);
mtx_mode = x;
mtx_loop = y;
mtx_mode = x &1; // Use x for selecting scroll up (0) or scroll left (1)
mtx_loop = y &1; // Use y for selecting no loop (0) or loop (1)
if (!mtx_state) { mtx_state = 1; }
}
@ -237,40 +232,36 @@ void MatrixDrawStringAt(uint16_t x, uint16_t y, char *str, uint16_t color, uint8
#ifdef USE_DISPLAY_MODES1TO5
void MatrixBufferScroll(uint8_t direction)
void MatrixPrintLog(uint8_t direction)
{
if (disp_log_buffer_idx != disp_log_buffer_ptr) {
if (!mtx_state) {
mtx_state = 1;
}
char* txt = (!mtx_done) ? DisplayLogBuffer('\370') : mtx_buffer;
if (txt != NULL) {
if (!mtx_state) { mtx_state = 1; }
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\370'; // = 0xF8
}
if (direction) {
MatrixScrollUp(disp_log_buffer[disp_log_buffer_ptr], 0);
} else {
if (!mtx_done) {
// Remove extra spaces
uint8_t space = 0;
uint8_t max_cols = (disp_log_buffer_cols < MTX_MAX_SCREEN_BUFFER) ? disp_log_buffer_cols : MTX_MAX_SCREEN_BUFFER;
mtx_buffer[0] = '\0';
for (byte i = 0; i < max_cols; i++) {
if (disp_log_buffer[disp_log_buffer_ptr][i] == ' ') {
if (txt[i] == ' ') {
space++;
} else {
space = 0;
}
if (space < 2) {
strncat(mtx_buffer, (const char*)disp_log_buffer[disp_log_buffer_ptr] +i, 1);
strncat(mtx_buffer, (const char*)txt +i, 1);
}
}
mtx_done = 1;
}
if (direction) {
MatrixScrollUp(mtx_buffer, 0);
} else {
MatrixScrollLeft(mtx_buffer, 0);
}
if (!mtx_state) {
DisplayLogBufferPtrInc();
}
if (!mtx_state) { mtx_done = 0; }
} else {
char disp_time[9]; // 13:45:43
@ -310,11 +301,11 @@ void MatrixRefresh() // Every second
break;
}
case 4:
MatrixBufferScroll(0);
MatrixPrintLog(0);
break;
case 1: // Time and user text
case 5: // Time, user text and MQTT
MatrixBufferScroll(1);
MatrixPrintLog(1);
break;
#endif // USE_DISPLAY_MODES1TO5
}

View File

@ -54,7 +54,7 @@ void Ili9341InitMode()
tft->setCursor(0, 0);
tft->setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
tft->setTextSize(2);
tft->println("HEADER");
// tft->println("HEADER");
tft_scroll = TFT_TOP;
}
@ -65,6 +65,11 @@ void Ili9341Init(uint8_t mode)
switch(mode) {
case DISPLAY_INIT_MODE:
Ili9341InitMode();
#ifdef USE_DISPLAY_MODES1TO5
if (Settings.display_rotate) {
DisplayClearScreenBuffer();
}
#endif // USE_DISPLAY_MODES1TO5
break;
case DISPLAY_INIT_PARTIAL:
case DISPLAY_INIT_FULL:
@ -82,6 +87,12 @@ void Ili9341InitDriver()
tft = new Adafruit_ILI9341(pin[GPIO_SPI_CS], pin[GPIO_SPI_DC]);
tft->begin();
#ifdef USE_DISPLAY_MODES1TO5
if (Settings.display_rotate) {
DisplayAllocScreenBuffer();
}
#endif // USE_DISPLAY_MODES1TO5
Ili9341InitMode();
}
}
@ -126,41 +137,49 @@ void Ili9341OnOff()
#ifdef USE_DISPLAY_MODES1TO5
void Ili9341PrintLogLine()
{
tft->setTextColor(ILI9341_CYAN, ILI9341_BLACK); // Add background color to solve flicker
tft->setCursor(0, tft_scroll);
byte size = Settings.display_size;
tft->setTextSize(size);
uint16_t theight = size * TFT_FONT_HEIGTH;
tft->fillRect(0, tft_scroll, tft->width(), theight, ILI9341_BLACK); // Erase line
char *pch = strchr(disp_log_buffer[disp_log_buffer_ptr],'~'); // = 0x7E (~) Replace degrees character (276 octal)
if (pch != NULL) {
disp_log_buffer[disp_log_buffer_ptr][pch - disp_log_buffer[disp_log_buffer_ptr]] = '\370'; // = 0xF8
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "[%s]"), disp_log_buffer[disp_log_buffer_ptr]);
AddLog(LOG_LEVEL_DEBUG);
tft->print(disp_log_buffer[disp_log_buffer_ptr]);
tft_scroll += theight;
if (tft_scroll >= (tft->height() - TFT_BOTTOM)) {
tft_scroll = TFT_TOP;
}
tft->scrollTo(tft_scroll);
}
void Ili9341PrintLog()
{
disp_refresh--;
if (!disp_refresh) {
disp_refresh = Settings.display_refresh;
disp_log_buffer_active = (disp_log_buffer_idx != disp_log_buffer_ptr);
if (disp_log_buffer_active) {
Ili9341PrintLogLine();
DisplayLogBufferPtrInc();
if (Settings.display_rotate) {
if (!disp_screen_buffer_cols) { DisplayAllocScreenBuffer(); }
}
char* txt = DisplayLogBuffer('\370');
if (txt != NULL) {
byte size = Settings.display_size;
uint16_t theight = size * TFT_FONT_HEIGTH;
tft->setTextSize(size);
tft->setTextColor(ILI9341_CYAN, ILI9341_BLACK); // Add background color to solve flicker
if (!Settings.display_rotate) { // Use hardware scroll
tft->setCursor(0, tft_scroll);
tft->fillRect(0, tft_scroll, tft->width(), theight, ILI9341_BLACK); // Erase line
tft->print(txt);
tft_scroll += theight;
if (tft_scroll >= (tft->height() - TFT_BOTTOM)) {
tft_scroll = TFT_TOP;
}
tft->scrollTo(tft_scroll);
} else {
uint8_t last_row = Settings.display_rows -1;
tft_scroll = theight; // Start below header
tft->setCursor(0, tft_scroll);
for (byte i = 0; i < last_row; i++) {
strlcpy(disp_screen_buffer[i], disp_screen_buffer[i +1], disp_screen_buffer_cols);
// tft->fillRect(0, tft_scroll, tft->width(), theight, ILI9341_BLACK); // Erase line
tft->print(disp_screen_buffer[i]);
tft_scroll += theight;
tft->setCursor(0, tft_scroll);
}
strlcpy(disp_screen_buffer[last_row], txt, disp_screen_buffer_cols);
DisplayFillScreen(last_row);
tft->print(disp_screen_buffer[last_row]);
}
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_APPLICATION "[%s]"), txt);
AddLog(LOG_LEVEL_DEBUG);
}
}
}
@ -168,17 +187,21 @@ void Ili9341PrintLog()
void Ili9341Refresh() // Every second
{
if (Settings.display_mode) { // Mode 0 is User text
char tftdt[21];
char disp_time[9]; // 13:45:43
char disp_date4[11]; // 24-04-2017
snprintf_P(disp_time, sizeof(disp_time), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second);
snprintf_P(disp_date4, sizeof(disp_date4), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year);
char tftdt[Settings.display_cols[0] +1];
char date4[11]; // 24-04-2017
char space[Settings.display_cols[0] - 17];
char time[9]; // 13:45:43
tft->setTextSize(2);
tft->setTextColor(ILI9341_YELLOW, ILI9341_BLACK); // Add background color to solve flicker
tft->setTextColor(ILI9341_YELLOW, ILI9341_RED); // Add background color to solve flicker
tft->setCursor(0, 0);
snprintf_P(tftdt, sizeof(tftdt), PSTR("%s %s"), disp_date4, disp_time);
snprintf_P(date4, sizeof(date4), PSTR("%02d" D_MONTH_DAY_SEPARATOR "%02d" D_YEAR_MONTH_SEPARATOR "%04d"), RtcTime.day_of_month, RtcTime.month, RtcTime.year);
memset(space, 0x20, sizeof(space));
space[sizeof(space) -1] = '\0';
snprintf_P(time, sizeof(time), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d"), RtcTime.hour, RtcTime.minute, RtcTime.second);
snprintf_P(tftdt, sizeof(tftdt), PSTR("%s%s%s"), date4, space, time);
tft->print(tftdt);
switch (Settings.display_mode) {