Просмотр исходного кода

✨ MarlinUI for Ender 3 v2 DWIN LCD (#22594)

Co-Authored-By: Taylor Talkington <taylor.talkington@gmail.com>
Scott Lahteine 3 лет назад
Родитель
Сommit
7d416bd055

+ 6 - 0
Marlin/Configuration.h

@@ -2746,6 +2746,12 @@
 //
 //#define DWIN_CREALITY_LCD
 
+//
+// MarlinUI for Creality's DWIN display (and others)
+//
+//#define DWIN_MARLINUI_PORTRAIT
+//#define DWIN_MARLINUI_LANDSCAPE
+
 //
 // Touch Screen Settings
 //

+ 13 - 11
Marlin/Configuration_adv.h

@@ -1306,7 +1306,7 @@
 
 // LCD Print Progress options
 #if EITHER(SDSUPPORT, LCD_SET_PROGRESS_MANUALLY)
-  #if ANY(HAS_MARLINUI_U8GLIB, EXTENSIBLE_UI, HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL)
+  #if ANY(HAS_MARLINUI_U8GLIB, EXTENSIBLE_UI, HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL, IS_DWIN_MARLINUI)
     //#define SHOW_REMAINING_TIME         // Display estimated time to completion
     #if ENABLED(SHOW_REMAINING_TIME)
       //#define USE_M73_REMAINING_TIME    // Use remaining time from M73 command instead of estimation
@@ -1579,16 +1579,10 @@
  * printing performance versus fast display updates.
  */
 #if HAS_MARLINUI_U8GLIB
-  // Show SD percentage next to the progress bar
-  //#define SHOW_SD_PERCENT
-
   // Save many cycles by drawing a hollow frame or no frame on the Info Screen
   //#define XYZ_NO_FRAME
   #define XYZ_HOLLOW_FRAME
 
-  // Enable to save many cycles by drawing a hollow frame on Menu Screens
-  #define MENU_HOLLOW_FRAME
-
   // A bigger font is available for edit items. Costs 3120 bytes of PROGMEM.
   // Western only. Not available for Cyrillic, Kana, Turkish, Greek, or Chinese.
   //#define USE_BIG_EDIT_FONT
@@ -1597,9 +1591,6 @@
   // Western only. Not available for Cyrillic, Kana, Turkish, Greek, or Chinese.
   //#define USE_SMALL_INFOFONT
 
-  // Swap the CW/CCW indicators in the graphics overlay
-  //#define OVERLAY_GFX_REVERSE
-
   /**
    * ST7920-based LCDs can emulate a 16 x 4 character display using
    * the ST7920 character-generator for very fast screen updates.
@@ -1651,6 +1642,17 @@
 
 #endif // HAS_MARLINUI_U8GLIB
 
+#if HAS_MARLINUI_U8GLIB || IS_DWIN_MARLINUI
+  // Show SD percentage next to the progress bar
+  //#define SHOW_SD_PERCENT
+
+  // Enable to save many cycles by drawing a hollow frame on Menu Screens
+  #define MENU_HOLLOW_FRAME
+
+  // Swap the CW/CCW indicators in the graphics overlay
+  //#define OVERLAY_GFX_REVERSE
+#endif
+
 //
 // Additional options for DGUS / DWIN displays
 //
@@ -1716,7 +1718,7 @@
 //
 // Specify additional languages for the UI. Default specified by LCD_LANGUAGE.
 //
-#if ANY(DOGLCD, TFT_COLOR_UI, TOUCH_UI_FTDI_EVE)
+#if ANY(DOGLCD, TFT_COLOR_UI, TOUCH_UI_FTDI_EVE, IS_DWIN_MARLINUI)
   //#define LCD_LANGUAGE_2 fr
   //#define LCD_LANGUAGE_3 de
   //#define LCD_LANGUAGE_4 es

+ 2 - 2
Marlin/src/feature/pause.cpp

@@ -238,8 +238,8 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load
 
     if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_PURGE);
 
-    TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(PSTR("Filament Purging...")));
-    TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Filament Purging..."), CONTINUE_STR));
+    TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(GET_TEXT(MSG_FILAMENT_CHANGE_PURGE)));
+    TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, GET_TEXT(MSG_FILAMENT_CHANGE_PURGE), CONTINUE_STR));
     wait_for_user = true; // A click or M108 breaks the purge_length loop
     for (float purge_count = purge_length; purge_count > 0 && wait_for_user; --purge_count)
       unscaled_e_move(1, ADVANCED_PAUSE_PURGE_FEEDRATE);

+ 5 - 2
Marlin/src/inc/Conditionals_LCD.h

@@ -488,7 +488,10 @@
     #define HAS_MARLINUI_U8GLIB 1
   #elif IS_TFTGLCD_PANEL
     // Neither DOGM nor HD44780. Fully customized interface.
-  #elif DISABLED(HAS_GRAPHICAL_TFT)
+  #elif IS_DWIN_MARLINUI
+    // Since HAS_MARLINUI_U8GLIB refers to U8G displays
+    // the DWIN display can define its own flags
+  #elif !HAS_GRAPHICAL_TFT
     #define HAS_MARLINUI_HD44780 1
   #endif
 #endif
@@ -1087,7 +1090,7 @@
   #define HAS_ETHERNET 1
 #endif
 
-#if ENABLED(DWIN_CREALITY_LCD)
+#if EITHER(DWIN_CREALITY_LCD, IS_DWIN_MARLINUI)
   #define SERIAL_CATCHALL 0
   #ifndef LCD_SERIAL_PORT
     #if MB(BTT_SKR_MINI_E3_V1_0, BTT_SKR_MINI_E3_V1_2, BTT_SKR_MINI_E3_V2_0, BTT_SKR_E3_TURBO)

+ 5 - 1
Marlin/src/inc/Conditionals_post.h

@@ -461,7 +461,7 @@
 
 #endif
 
-#if ANY(HAS_GRAPHICAL_TFT, LCD_USE_DMA_FSMC, HAS_FSMC_GRAPHICAL_TFT, HAS_SPI_GRAPHICAL_TFT) || !PIN_EXISTS(SD_DETECT)
+#if ANY(HAS_GRAPHICAL_TFT, LCD_USE_DMA_FSMC, HAS_FSMC_GRAPHICAL_TFT, HAS_SPI_GRAPHICAL_TFT, IS_DWIN_MARLINUI) || !PIN_EXISTS(SD_DETECT)
   #define NO_LCD_REINIT 1  // Suppress LCD re-initialization
 #endif
 
@@ -3258,6 +3258,8 @@
   #ifndef LCD_WIDTH
     #if HAS_MARLINUI_U8GLIB
       #define LCD_WIDTH 21
+    #elif IS_DWIN_MARLINUI
+      // Defined by header
     #else
       #define LCD_WIDTH TERN(IS_ULTIPANEL, 20, 16)
     #endif
@@ -3265,6 +3267,8 @@
   #ifndef LCD_HEIGHT
     #if HAS_MARLINUI_U8GLIB
       #define LCD_HEIGHT 5
+    #elif IS_DWIN_MARLINUI
+      // Defined by header
     #else
       #define LCD_HEIGHT TERN(IS_ULTIPANEL, 4, 2)
     #endif

+ 4 - 3
Marlin/src/inc/SanityCheck.h

@@ -798,8 +798,8 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
     #error "PROGRESS_MSG_EXPIRE must be greater than or equal to 0."
   #endif
 #elif ENABLED(LCD_SET_PROGRESS_MANUALLY)
-  #if NONE(HAS_MARLINUI_U8GLIB, HAS_GRAPHICAL_TFT, HAS_MARLINUI_HD44780, EXTENSIBLE_UI)
-    #error "LCD_SET_PROGRESS_MANUALLY requires LCD_PROGRESS_BAR, Character LCD, Graphical LCD, TFT, or EXTENSIBLE_UI."
+  #if NONE(HAS_MARLINUI_U8GLIB, HAS_GRAPHICAL_TFT, HAS_MARLINUI_HD44780, EXTENSIBLE_UI, IS_DWIN_MARLINUI)
+    #error "LCD_SET_PROGRESS_MANUALLY requires LCD_PROGRESS_BAR, Character LCD, Graphical LCD, TFT, EXTENSIBLE_UI, OR DWIN MarlinUI."
   #endif
 #endif
 
@@ -1721,7 +1721,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
   #endif
 #endif
 
-#if ENABLED(MESH_EDIT_GFX_OVERLAY) && !BOTH(AUTO_BED_LEVELING_UBL, HAS_MARLINUI_U8GLIB)
+#if ENABLED(MESH_EDIT_GFX_OVERLAY) && !(ENABLED(AUTO_BED_LEVELING_UBL) && EITHER(HAS_MARLINUI_U8GLIB, IS_DWIN_MARLINUI))
   #error "MESH_EDIT_GFX_OVERLAY requires AUTO_BED_LEVELING_UBL and a Graphical LCD."
 #endif
 
@@ -2640,6 +2640,7 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS
   + COUNT_ENABLED(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON, ANYCUBIC_TFT35) \
   + COUNT_ENABLED(DGUS_LCD_UI_ORIGIN, DGUS_LCD_UI_FYSETC, DGUS_LCD_UI_HIPRECY, DGUS_LCD_UI_MKS) \
   + COUNT_ENABLED(ENDER2_STOCKDISPLAY, CR10_STOCKDISPLAY, DWIN_CREALITY_LCD) \
+  + COUNT_ENABLED(DWIN_MARLINUI_PORTRAIT, DWIN_MARLINUI_LANDSCAPE) \
   + COUNT_ENABLED(FYSETC_MINI_12864_X_X, FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0, FYSETC_MINI_12864_2_1, FYSETC_GENERIC_12864_1_1) \
   + COUNT_ENABLED(LCD_SAINSMART_I2C_1602, LCD_SAINSMART_I2C_2004) \
   + COUNT_ENABLED(MKS_12864OLED, MKS_12864OLED_SSD1306) \

+ 470 - 0
Marlin/src/lcd/e3v2/marlinui/dwin_lcd.cpp

@@ -0,0 +1,470 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/********************************************************************************
+ * @file     lcd/e3v2/marlinui/dwin_lcd.cpp
+ * @brief    DWIN screen control functions
+ ********************************************************************************/
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if IS_DWIN_MARLINUI
+
+#include "../../../inc/MarlinConfig.h"
+
+#include "dwin_lcd.h"
+#include <string.h> // for memset
+
+//#define DEBUG_OUT 1
+#include "../../../core/debug_out.h"
+
+// Make sure DWIN_SendBuf is large enough to hold the largest string plus draw command and tail.
+// Assume the narrowest (6 pixel) font and 2-byte gb2312-encoded characters.
+uint8_t DWIN_SendBuf[11 + DWIN_WIDTH / 6 * 2] = { 0xAA };
+uint8_t DWIN_BufTail[4] = { 0xCC, 0x33, 0xC3, 0x3C };
+uint8_t databuf[26] = { 0 };
+uint8_t receivedType;
+
+int recnum = 0;
+
+inline void DWIN_Byte(size_t &i, const uint16_t bval) {
+  DWIN_SendBuf[++i] = bval;
+}
+
+inline void DWIN_Word(size_t &i, const uint16_t wval) {
+  DWIN_SendBuf[++i] = wval >> 8;
+  DWIN_SendBuf[++i] = wval & 0xFF;
+}
+
+inline void DWIN_Long(size_t &i, const uint32_t lval) {
+  DWIN_SendBuf[++i] = (lval >> 24) & 0xFF;
+  DWIN_SendBuf[++i] = (lval >> 16) & 0xFF;
+  DWIN_SendBuf[++i] = (lval >>  8) & 0xFF;
+  DWIN_SendBuf[++i] = lval & 0xFF;
+}
+
+inline void DWIN_String(size_t &i, char * const string) {
+  const size_t len = _MIN(sizeof(DWIN_SendBuf) - i, strlen(string));
+  memcpy(&DWIN_SendBuf[i+1], string, len);
+  i += len;
+}
+
+inline void DWIN_String(size_t &i, const __FlashStringHelper * string) {
+  if (!string) return;
+  const size_t len = strlen_P((PGM_P)string); // cast it to PGM_P, which is basically const char *, and measure it using the _P version of strlen.
+  if (len == 0) return;
+  memcpy(&DWIN_SendBuf[i+1], string, len);
+  i += len;
+}
+
+// Send the data in the buffer and the packet end
+inline void DWIN_Send(size_t &i) {
+  ++i;
+  LOOP_L_N(n, i) { LCD_SERIAL.write(DWIN_SendBuf[n]); delayMicroseconds(1); }
+  LOOP_L_N(n, 4) { LCD_SERIAL.write(DWIN_BufTail[n]); delayMicroseconds(1); }
+}
+
+/*-------------------------------------- System variable function --------------------------------------*/
+
+// Handshake (1: Success, 0: Fail)
+bool DWIN_Handshake(void) {
+  #ifndef LCD_BAUDRATE
+    #define LCD_BAUDRATE 115200
+  #endif
+  LCD_SERIAL.begin(LCD_BAUDRATE);
+  const millis_t serial_connect_timeout = millis() + 1000UL;
+  while (!LCD_SERIAL.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
+
+  size_t i = 0;
+  DWIN_Byte(i, 0x00);
+  DWIN_Send(i);
+
+  while (LCD_SERIAL.available() > 0 && recnum < (signed)sizeof(databuf)) {
+    databuf[recnum] = LCD_SERIAL.read();
+    // ignore the invalid data
+    if (databuf[0] != FHONE) { // prevent the program from running.
+      if (recnum > 0) {
+        recnum = 0;
+        ZERO(databuf);
+      }
+      continue;
+    }
+    delay(10);
+    recnum++;
+  }
+
+  return ( recnum >= 3
+        && databuf[0] == FHONE
+        && databuf[1] == '\0'
+        && databuf[2] == 'O'
+        && databuf[3] == 'K' );
+}
+
+void DWIN_Startup(void) {
+  DEBUG_ECHOPGM("\r\nDWIN handshake ");
+  delay(750);   // Delay here or init later in the boot process
+  const bool success = DWIN_Handshake();
+  if (success) DEBUG_ECHOLNPGM("ok."); else DEBUG_ECHOLNPGM("error.");
+  DWIN_Frame_SetDir(TERN(DWIN_MARLINUI_LANDSCAPE, 0, 1));
+  DWIN_Frame_Clear(Color_Bg_Black); // MarlinUI handles the bootscreen so just clear here
+  DWIN_UpdateLCD();
+}
+
+// Set the backlight luminance
+//  luminance: (0x00-0xFF)
+void DWIN_Backlight_SetLuminance(const uint8_t luminance) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x30);
+  DWIN_Byte(i, _MAX(luminance, 0x1F));
+  DWIN_Send(i);
+}
+
+// Set screen display direction
+//  dir: 0=0°, 1=90°, 2=180°, 3=270°
+void DWIN_Frame_SetDir(uint8_t dir) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x34);
+  DWIN_Byte(i, 0x5A);
+  DWIN_Byte(i, 0xA5);
+  DWIN_Byte(i, dir);
+  DWIN_Send(i);
+}
+
+// Update display
+void DWIN_UpdateLCD(void) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x3D);
+  DWIN_Send(i);
+}
+
+/*---------------------------------------- Drawing functions ----------------------------------------*/
+
+// Clear screen
+//  color: Clear screen color
+void DWIN_Frame_Clear(const uint16_t color) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x01);
+  DWIN_Word(i, color);
+  DWIN_Send(i);
+}
+
+// Draw a point
+//  width: point width   0x01-0x0F
+//  height: point height 0x01-0x0F
+//  x,y: upper left point
+void DWIN_Draw_Point(uint16_t color, uint8_t width, uint8_t height, uint16_t x, uint16_t y) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x02);
+  DWIN_Word(i, color);
+  DWIN_Byte(i, width);
+  DWIN_Byte(i, height);
+  DWIN_Word(i, x);
+  DWIN_Word(i, y);
+  DWIN_Send(i);
+}
+
+// Draw a line
+//  color: Line segment color
+//  xStart/yStart: Start point
+//  xEnd/yEnd: End point
+void DWIN_Draw_Line(uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x03);
+  DWIN_Word(i, color);
+  DWIN_Word(i, xStart);
+  DWIN_Word(i, yStart);
+  DWIN_Word(i, xEnd);
+  DWIN_Word(i, yEnd);
+  DWIN_Send(i);
+}
+
+// Draw a rectangle
+//  mode: 0=frame, 1=fill, 2=XOR fill
+//  color: Rectangle color
+//  xStart/yStart: upper left point
+//  xEnd/yEnd: lower right point
+void DWIN_Draw_Rectangle(uint8_t mode, uint16_t color,
+                         uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x05);
+  DWIN_Byte(i, mode);
+  DWIN_Word(i, color);
+  DWIN_Word(i, xStart);
+  DWIN_Word(i, yStart);
+  DWIN_Word(i, xEnd);
+  DWIN_Word(i, yEnd);
+  DWIN_Send(i);
+}
+
+// Move a screen area
+//  mode: 0, circle shift; 1, translation
+//  dir: 0=left, 1=right, 2=up, 3=down
+//  dis: Distance
+//  color: Fill color
+//  xStart/yStart: upper left point
+//  xEnd/yEnd: bottom right point
+void DWIN_Frame_AreaMove(uint8_t mode, uint8_t dir, uint16_t dis,
+                         uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x09);
+  DWIN_Byte(i, (mode << 7) | dir);
+  DWIN_Word(i, dis);
+  DWIN_Word(i, color);
+  DWIN_Word(i, xStart);
+  DWIN_Word(i, yStart);
+  DWIN_Word(i, xEnd);
+  DWIN_Word(i, yEnd);
+  DWIN_Send(i);
+}
+
+/*---------------------------------------- Text related functions ----------------------------------------*/
+
+// Draw a string
+//  bShow: true=display background color; false=don't display background color
+//  size: Font size
+//  color: Character color
+//  bColor: Background color
+//  x/y: Upper-left coordinate of the string
+//  *string: The string
+void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x, uint16_t y, char *string) {
+  uint8_t widthAdjust = 0;
+  size_t i = 0;
+  DWIN_Byte(i, 0x11);
+  // Bit 7: widthAdjust
+  // Bit 6: bShow
+  // Bit 5-4: Unused (0)
+  // Bit 3-0: size
+  DWIN_Byte(i, (widthAdjust * 0x80) | (bShow * 0x40) | size);
+  DWIN_Word(i, color);
+  DWIN_Word(i, bColor);
+  DWIN_Word(i, x);
+  DWIN_Word(i, y);
+  DWIN_String(i, string);
+  DWIN_Send(i);
+}
+
+// Draw a positive integer
+//  bShow: true=display background color; false=don't display background color
+//  zeroFill: true=zero fill; false=no zero fill
+//  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
+//  size: Font size
+//  color: Character color
+//  bColor: Background color
+//  iNum: Number of digits
+//  x/y: Upper-left coordinate
+//  value: Integer value
+void DWIN_Draw_IntValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
+                          uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, uint16_t value) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x14);
+  // Bit 7: bshow
+  // Bit 6: 1 = signed; 0 = unsigned number;
+  // Bit 5: zeroFill
+  // Bit 4: zeroMode
+  // Bit 3-0: size
+  DWIN_Byte(i, (bShow * 0x80) | (zeroFill * 0x20) | (zeroMode * 0x10) | size);
+  DWIN_Word(i, color);
+  DWIN_Word(i, bColor);
+  DWIN_Byte(i, iNum);
+  DWIN_Byte(i, 0); // fNum
+  DWIN_Word(i, x);
+  DWIN_Word(i, y);
+  #if 0
+    for (char count = 0; count < 8; count++) {
+      DWIN_Byte(i, value);
+      value >>= 8;
+      if (!(value & 0xFF)) break;
+    }
+  #else
+    // Write a big-endian 64 bit integer
+    const size_t p = i + 1;
+    for (char count = 8; count--;) { // 7..0
+      ++i;
+      DWIN_SendBuf[p + count] = value;
+      value >>= 8;
+    }
+  #endif
+
+  DWIN_Send(i);
+}
+
+// Draw a floating point number
+//  bShow: true=display background color; false=don't display background color
+//  zeroFill: true=zero fill; false=no zero fill
+//  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
+//  size: Font size
+//  color: Character color
+//  bColor: Background color
+//  iNum: Number of whole digits
+//  fNum: Number of decimal digits
+//  x/y: Upper-left point
+//  value: Float value
+void DWIN_Draw_FloatValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
+                            uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, long value) {
+  //uint8_t *fvalue = (uint8_t*)&value;
+  size_t i = 0;
+  DWIN_Byte(i, 0x14);
+  DWIN_Byte(i, (bShow * 0x80) | (zeroFill * 0x20) | (zeroMode * 0x10) | size);
+  DWIN_Word(i, color);
+  DWIN_Word(i, bColor);
+  DWIN_Byte(i, iNum);
+  DWIN_Byte(i, fNum);
+  DWIN_Word(i, x);
+  DWIN_Word(i, y);
+  DWIN_Long(i, value);
+  /*
+  DWIN_Byte(i, fvalue[3]);
+  DWIN_Byte(i, fvalue[2]);
+  DWIN_Byte(i, fvalue[1]);
+  DWIN_Byte(i, fvalue[0]);
+  */
+  DWIN_Send(i);
+}
+
+/*---------------------------------------- Picture related functions ----------------------------------------*/
+
+// Draw JPG and cached in #0 virtual display area
+// id: Picture ID
+void DWIN_JPG_ShowAndCache(const uint8_t id) {
+  size_t i = 0;
+  DWIN_Word(i, 0x2200);
+  DWIN_Byte(i, id);
+  DWIN_Send(i);     // AA 23 00 00 00 00 08 00 01 02 03 CC 33 C3 3C
+}
+
+// Draw an Icon
+//  libID: Icon library ID
+//  picID: Icon ID
+//  x/y: Upper-left point
+void DWIN_ICON_Show(uint8_t libID, uint8_t picID, uint16_t x, uint16_t y) {
+  NOMORE(x, DWIN_WIDTH - 1);
+  NOMORE(y, DWIN_HEIGHT - 1); // -- ozy -- srl
+  size_t i = 0;
+  DWIN_Byte(i, 0x23);
+  DWIN_Word(i, x);
+  DWIN_Word(i, y);
+  DWIN_Byte(i, 0x80 | libID);
+  //DWIN_Byte(i, libID);
+  DWIN_Byte(i, picID);
+  DWIN_Send(i);
+}
+
+// Unzip the JPG picture to a virtual display area
+//  n: Cache index
+//  id: Picture ID
+void DWIN_JPG_CacheToN(uint8_t n, uint8_t id) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x25);
+  DWIN_Byte(i, n);
+  DWIN_Byte(i, id);
+  DWIN_Send(i);
+}
+
+// Copy area from virtual display area to current screen
+//  cacheID: virtual area number
+//  xStart/yStart: Upper-left of virtual area
+//  xEnd/yEnd: Lower-right of virtual area
+//  x/y: Screen paste point
+void DWIN_Frame_AreaCopy(uint8_t cacheID, uint16_t xStart, uint16_t yStart,
+                         uint16_t xEnd, uint16_t yEnd, uint16_t x, uint16_t y) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x27);
+  DWIN_Byte(i, 0x80 | cacheID);
+  DWIN_Word(i, xStart);
+  DWIN_Word(i, yStart);
+  DWIN_Word(i, xEnd);
+  DWIN_Word(i, yEnd);
+  DWIN_Word(i, x);
+  DWIN_Word(i, y);
+  DWIN_Send(i);
+}
+
+// Animate a series of icons
+//  animID: Animation ID; 0x00-0x0F
+//  animate: true on; false off;
+//  libID: Icon library ID
+//  picIDs: Icon starting ID
+//  picIDe: Icon ending ID
+//  x/y: Upper-left point
+//  interval: Display time interval, unit 10mS
+void DWIN_ICON_Animation(uint8_t animID, bool animate, uint8_t libID, uint8_t picIDs, uint8_t picIDe, uint16_t x, uint16_t y, uint16_t interval) {
+  NOMORE(x, DWIN_WIDTH - 1);
+  NOMORE(y, DWIN_HEIGHT - 1); // -- ozy -- srl
+  size_t i = 0;
+  DWIN_Byte(i, 0x28);
+  DWIN_Word(i, x);
+  DWIN_Word(i, y);
+  // Bit 7: animation on or off
+  // Bit 6: start from begin or end
+  // Bit 5-4: unused (0)
+  // Bit 3-0: animID
+  DWIN_Byte(i, (animate * 0x80) | 0x40 | animID);
+  DWIN_Byte(i, libID);
+  DWIN_Byte(i, picIDs);
+  DWIN_Byte(i, picIDe);
+  DWIN_Byte(i, interval);
+  DWIN_Send(i);
+}
+
+// Animation Control
+//  state: 16 bits, each bit is the state of an animation id
+void DWIN_ICON_AnimationControl(uint16_t state) {
+  size_t i = 0;
+  DWIN_Byte(i, 0x29);
+  DWIN_Word(i, state);
+  DWIN_Send(i);
+}
+
+/*---------------------------------------- Memory functions ----------------------------------------*/
+// The LCD has an additional 32KB SRAM and 16KB Flash
+
+// Data can be written to the sram and save to one of the jpeg page files
+
+// Write Data Memory
+//  command 0x31
+//  Type: Write memory selection; 0x5A=SRAM; 0xA5=Flash
+//  Address: Write data memory address; 0x000-0x7FFF for SRAM; 0x000-0x3FFF for Flash
+//  Data: data
+//
+//  Flash writing returns 0xA5 0x4F 0x4B
+
+// Read Data Memory
+//  command 0x32
+//  Type: Read memory selection; 0x5A=SRAM; 0xA5=Flash
+//  Address: Read data memory address; 0x000-0x7FFF for SRAM; 0x000-0x3FFF for Flash
+//  Length: leangth of data to read; 0x01-0xF0
+//
+//  Response:
+//    Type, Address, Length, Data
+
+// Write Picture Memory
+//  Write the contents of the 32KB SRAM data memory into the designated image memory space
+//  Issued: 0x5A, 0xA5, PIC_ID
+//  Response: 0xA5 0x4F 0x4B
+//
+//  command 0x33
+//  0x5A, 0xA5
+//  PicId: Picture Memory location, 0x00-0x0F
+//
+//  Flash writing returns 0xA5 0x4F 0x4B
+
+#endif // IS_DWIN_MARLINUI

+ 302 - 0
Marlin/src/lcd/e3v2/marlinui/dwin_lcd.h

@@ -0,0 +1,302 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/********************************************************************************
+ * @file     lcd/e3v2/marlinui/dwin_lcd.h
+ * @brief    DWIN screen control functions
+ ********************************************************************************/
+
+#include <stdint.h>
+
+#define RECEIVED_NO_DATA         0x00
+#define RECEIVED_SHAKE_HAND_ACK  0x01
+
+#define FHONE                    0xAA
+
+#define DWIN_SCROLL_UP   2
+#define DWIN_SCROLL_DOWN 3
+
+#if DISABLED(DWIN_MARLINUI_LANDSCAPE)
+  #define DWIN_WIDTH  272
+  #define DWIN_HEIGHT 480
+#else
+  #define DWIN_WIDTH  480
+  #define DWIN_HEIGHT 272
+#endif
+
+// Picture ID
+#define DWIN_Boot_Horiz      0
+#define DWIN_Boot_Vert       1
+#define DWIN_MarlinUI_Assets 2
+
+/**
+ * 3-.0:The font size, 0x00-0x09, corresponds to the font size below:
+ * 0x00=6*12   0x01=8*16   0x02=10*20  0x03=12*24  0x04=14*28
+ * 0x05=16*32  0x06=20*40  0x07=24*48  0x08=28*56  0x09=32*64
+ */
+#define font6x12  0x00
+#define font8x16  0x01
+#define font10x20 0x02
+#define font12x24 0x03
+#define font14x28 0x04
+#define font16x32 0x05
+#define font20x40 0x06
+#define font24x48 0x07
+#define font28x56 0x08
+#define font32x64 0x09
+
+#define DWIN_FONT_MENU  font10x20
+#define DWIN_FONT_STAT  font14x28
+#define DWIN_FONT_HEAD  font10x20
+#define DWIN_FONT_ALERT font14x28
+
+// Color
+#define Color_White       0xFFFF
+#define Color_Yellow      0xFF0F
+#define Color_Error_Red   0xB000  // Error!
+#define Color_Bg_Red      0xF00F  // Red background color
+#define Color_Bg_Window   0x31E8  // Popup background color
+#define Color_Bg_Heading  0x3344  // Static Heading
+#define Color_Bg_Blue     0x1125  // Dark blue background color
+#define Color_Bg_Black    0x0841  // Black background color
+#define Color_IconBlue    0x45FA  // Lighter blue that matches icons/accents
+#define Popup_Text_Color  0xD6BA  // Popup font background color
+#define Line_Color        0x3A6A  // Split line color
+#define Rectangle_Color   0xEE2F  // Blue square cursor color
+#define Percent_Color     0xFE29  // Percentage color
+#define BarFill_Color     0x10E4  // Fill color of progress bar
+#define Select_Color      0x33BB  // Selected color
+
+// Character matrix width x height
+//#define LCD_WIDTH ((DWIN_WIDTH) / 8)
+//#define LCD_HEIGHT ((DWIN_HEIGHT) / 12)
+
+// ICON ID
+#define BOOT_ICON           3 // Icon set file 3.ICO
+#define ICON                4 // Icon set file 4.ICO
+
+// MarlinUI Boot Icons
+#define ICON_MarlinBoot            0
+#define ICON_OpenSource            1
+#define ICON_GitHubURL             2
+#define ICON_MarlinURL             3
+#define ICON_Copyright             4
+
+// MarlinUI Icons
+#define ICON_LOGO_Marlin           0
+#define ICON_HotendOff             1
+#define ICON_HotendOn              2
+#define ICON_BedOff                3
+#define ICON_BedOn                 4
+#define ICON_Fan0                  5
+#define ICON_Fan1                  6
+#define ICON_Fan2                  7
+#define ICON_Fan3                  8
+#define ICON_Halted                9
+#define ICON_Question             10
+#define ICON_Alert                11
+#define ICON_RotateCW             12
+#define ICON_RotateCCW            13
+#define ICON_UpArrow              14
+#define ICON_DownArrow            15
+#define ICON_BedLine              16
+
+#define ICON_AdvSet               ICON_Language
+#define ICON_HomeOff              ICON_AdvSet
+#define ICON_HomeOffX             ICON_StepX
+#define ICON_HomeOffY             ICON_StepY
+#define ICON_HomeOffZ             ICON_StepZ
+#define ICON_ProbeOff             ICON_AdvSet
+#define ICON_ProbeOffX            ICON_StepX
+#define ICON_ProbeOffY            ICON_StepY
+#define ICON_PIDNozzle            ICON_SetEndTemp
+#define ICON_PIDbed               ICON_SetBedTemp
+
+/*-------------------------------------- System variable function --------------------------------------*/
+
+// Handshake (1: Success, 0: Fail)
+bool DWIN_Handshake(void);
+
+// Common DWIN startup
+void DWIN_Startup(void);
+
+// Set the backlight luminance
+//  luminance: (0x00-0xFF)
+void DWIN_Backlight_SetLuminance(const uint8_t luminance);
+
+// Set screen display direction
+//  dir: 0=0°, 1=90°, 2=180°, 3=270°
+void DWIN_Frame_SetDir(uint8_t dir);
+
+// Update display
+void DWIN_UpdateLCD(void);
+
+/*---------------------------------------- Drawing functions ----------------------------------------*/
+
+// Clear screen
+//  color: Clear screen color
+void DWIN_Frame_Clear(const uint16_t color);
+
+// Draw a point
+//  color: point color
+//  width: point width   0x01-0x0F
+//  height: point height 0x01-0x0F
+//  x,y: upper left point
+void DWIN_Draw_Point(uint16_t color, uint8_t width, uint8_t height, uint16_t x, uint16_t y);
+
+// Draw a line
+//  color: Line segment color
+//  xStart/yStart: Start point
+//  xEnd/yEnd: End point
+void DWIN_Draw_Line(uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd);
+
+// Draw a Horizontal line
+//  color: Line segment color
+//  xStart/yStart: Start point
+//  xLength: Line Length
+inline void DWIN_Draw_HLine(uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xLength) {
+  DWIN_Draw_Line(color, xStart, yStart, xStart + xLength - 1, yStart);
+}
+
+// Draw a Vertical line
+//  color: Line segment color
+//  xStart/yStart: Start point
+//  yLength: Line Length
+inline void DWIN_Draw_VLine(uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t yLength) {
+  DWIN_Draw_Line(color, xStart, yStart, xStart, yStart + yLength - 1);
+}
+
+// Draw a rectangle
+//  mode: 0=frame, 1=fill, 2=XOR fill
+//  color: Rectangle color
+//  xStart/yStart: upper left point
+//  xEnd/yEnd: lower right point
+void DWIN_Draw_Rectangle(uint8_t mode, uint16_t color,
+                         uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd);
+
+// Draw a box
+//  mode: 0=frame, 1=fill, 2=XOR fill
+//  color: Rectangle color
+//  xStart/yStart: upper left point
+//  xSize/ySize: box size
+inline void DWIN_Draw_Box(uint8_t mode, uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xSize, uint16_t ySize) {
+  DWIN_Draw_Rectangle(mode, color, xStart, yStart, xStart + xSize - 1, yStart + ySize - 1);
+}
+
+// Move a screen area
+//  mode: 0, circle shift; 1, translation
+//  dir: 0=left, 1=right, 2=up, 3=down
+//  dis: Distance
+//  color: Fill color
+//  xStart/yStart: upper left point
+//  xEnd/yEnd: bottom right point
+void DWIN_Frame_AreaMove(uint8_t mode, uint8_t dir, uint16_t dis,
+                         uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd);
+
+/*---------------------------------------- Text related functions ----------------------------------------*/
+
+// Draw a string
+//  bShow: true=display background color; false=don't display background color
+//  size: Font size
+//  color: Character color
+//  bColor: Background color
+//  x/y: Upper-left coordinate of the string
+//  *string: The string
+void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x, uint16_t y, char *string);
+
+class __FlashStringHelper;
+
+inline void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x, uint16_t y, const __FlashStringHelper *title) {
+  DWIN_Draw_String(bShow, size, color, bColor, x, y, (char *)title);
+}
+
+// Draw a positive integer
+//  bShow: true=display background color; false=don't display background color
+//  zeroFill: true=zero fill; false=no zero fill
+//  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
+//  size: Font size
+//  color: Character color
+//  bColor: Background color
+//  iNum: Number of digits
+//  x/y: Upper-left coordinate
+//  value: Integer value
+void DWIN_Draw_IntValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
+                          uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, uint16_t value);
+
+// Draw a floating point number
+//  bShow: true=display background color; false=don't display background color
+//  zeroFill: true=zero fill; false=no zero fill
+//  zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
+//  size: Font size
+//  color: Character color
+//  bColor: Background color
+//  iNum: Number of whole digits
+//  fNum: Number of decimal digits
+//  x/y: Upper-left point
+//  value: Float value
+void DWIN_Draw_FloatValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
+                            uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, long value);
+
+/*---------------------------------------- Picture related functions ----------------------------------------*/
+
+// Draw JPG and cached in #0 virtual display area
+// id: Picture ID
+void DWIN_JPG_ShowAndCache(const uint8_t id);
+
+// Draw an Icon
+//  libID: Icon library ID
+//  picID: Icon ID
+//  x/y: Upper-left point
+void DWIN_ICON_Show(uint8_t libID, uint8_t picID, uint16_t x, uint16_t y);
+
+// Unzip the JPG picture to a virtual display area
+//  n: Cache index
+//  id: Picture ID
+void DWIN_JPG_CacheToN(uint8_t n, uint8_t id);
+
+// Unzip the JPG picture to virtual display area #1
+//  id: Picture ID
+inline void DWIN_JPG_CacheTo1(uint8_t id) { DWIN_JPG_CacheToN(1, id); }
+
+// Copy area from virtual display area to current screen
+//  cacheID: virtual area number
+//  xStart/yStart: Upper-left of virtual area
+//  xEnd/yEnd: Lower-right of virtual area
+//  x/y: Screen paste point
+void DWIN_Frame_AreaCopy(uint8_t cacheID, uint16_t xStart, uint16_t yStart,
+                         uint16_t xEnd, uint16_t yEnd, uint16_t x, uint16_t y);
+
+// Animate a series of icons
+//  animID: Animation ID  up to 16
+//  animate: animation on or off
+//  libID: Icon library ID
+//  picIDs: Icon starting ID
+//  picIDe: Icon ending ID
+//  x/y: Upper-left point
+//  interval: Display time interval, unit 10mS
+void DWIN_ICON_Animation(uint8_t animID, bool animate, uint8_t libID, uint8_t picIDs,
+                         uint8_t picIDe, uint16_t x, uint16_t y, uint16_t interval);
+
+// Animation Control
+//  state: 16 bits, each bit is the state of an animation id
+void DWIN_ICON_AnimationControl(uint16_t state);

+ 180 - 0
Marlin/src/lcd/e3v2/marlinui/dwin_string.cpp

@@ -0,0 +1,180 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../../inc/MarlinConfig.h"
+
+#if IS_DWIN_MARLINUI
+
+#include "dwin_string.h"
+//#include "../../fontutils.h"
+
+uint8_t DWIN_String::data[];
+uint16_t DWIN_String::span;
+uint8_t DWIN_String::len;
+
+void DWIN_String::set() {
+  //*data = 0x00;
+  memset(data, 0x00, sizeof(data));
+  span = 0;
+  len = 0;
+}
+
+uint8_t read_byte(uint8_t *byte) { return *byte; }
+
+/**
+ * Add a string, applying substitutions for the following characters:
+ *
+ *   = displays  '0'....'10' for indexes 0 - 10
+ *   ~ displays  '1'....'11' for indexes 0 - 10
+ *   * displays 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL)
+ */
+void DWIN_String::add(uint8_t *string, int8_t index, uint8_t *itemString) {
+  wchar_t wchar;
+
+  while (*string) {
+    string = get_utf8_value_cb(string, read_byte, &wchar);
+    if (wchar > 255) wchar |= 0x0080;
+    uint8_t ch = uint8_t(wchar & 0x00FF);
+
+    if (ch == '=' || ch == '~' || ch == '*') {
+      if (index >= 0) {
+        int8_t inum = index + ((ch == '=') ? 0 : LCD_FIRST_TOOL);
+        if (ch == '*') add_character('E');
+        if (inum >= 10) { add_character('0' + (inum / 10)); inum %= 10; }
+        add_character('0' + inum);
+      }
+      else {
+        add(index == -2 ? GET_TEXT(MSG_CHAMBER) : GET_TEXT(MSG_BED));
+      }
+      continue;
+    }
+    else if (ch == '$' && itemString) {
+      add(itemString);
+      continue;
+    }
+
+    add_character(ch);
+  }
+  eol();
+}
+
+void DWIN_String::add(uint8_t *string, uint8_t max_len) {
+  wchar_t wchar;
+  while (*string && max_len) {
+    string = get_utf8_value_cb(string, read_byte, &wchar);
+    /*
+    if (wchar > 255) wchar |= 0x0080;
+    uint8_t ch = uint8_t(wchar & 0x00FF);
+    add_character(ch);
+    */
+    add(wchar);
+    max_len--;
+  }
+  eol();
+}
+
+void DWIN_String::add(wchar_t character) {
+  int ret;
+  size_t idx = 0;
+  dwin_charmap_t pinval;
+  dwin_charmap_t *copy_address = nullptr;
+  pinval.uchar = character;
+  pinval.idx = -1;
+
+  // For 8-bit ASCII just print the single character
+  char str[] = { '?', 0 };
+  if (character < 255) {
+    str[0] = (char)character;
+  }
+  else {
+    copy_address = nullptr;
+    ret = pf_bsearch_r((void *)g_dwin_charmap_device, COUNT(g_dwin_charmap_device), pf_bsearch_cb_comp_dwinmap_pgm, (void *)&pinval, &idx);
+    if (ret >= 0) {
+      copy_address = (dwin_charmap_t*)(g_dwin_charmap_device + idx);
+    }
+    else {
+      ret = pf_bsearch_r((void *)g_dwin_charmap_common, COUNT(g_dwin_charmap_common), pf_bsearch_cb_comp_dwinmap_pgm, (void *)&pinval, &idx);
+      if (ret >= 0)
+        copy_address = (dwin_charmap_t*)(g_dwin_charmap_common + idx);
+    }
+    if (ret >= 0) {
+      dwin_charmap_t localval;
+      memcpy_P(&localval, copy_address, sizeof(localval));
+      str[0] = localval.idx;
+      str[1] = localval.idx2;
+    }
+  }
+  if (str[0]) add_character(str[0]);
+  if (str[1]) add_character(str[1]);
+}
+
+void DWIN_String::add_character(uint8_t character) {
+  if (len < MAX_STRING_LENGTH) {
+    data[len] = character;
+    len++;
+    //span += glyph(character)->DWidth;
+  }
+}
+
+void DWIN_String::rtrim(uint8_t character) {
+  while (len) {
+    if (data[len - 1] == 0x20 || data[len - 1] == character) {
+      len--;
+      //span -= glyph(data[length])->DWidth;
+      eol();
+    }
+    else
+      break;
+  }
+}
+
+void DWIN_String::ltrim(uint8_t character) {
+  uint16_t i, j;
+  for (i = 0; (i < len) && (data[i] == 0x20 || data[i] == character); i++) {
+    //span -= glyph(data[i])->DWidth;
+  }
+  if (i == 0) return;
+  for (j = 0; i < len; data[j++] = data[i++]);
+  len = j;
+  eol();
+}
+
+void DWIN_String::trim(uint8_t character) {
+  rtrim(character);
+  ltrim(character);
+}
+
+/* return v1 - v2 */
+int dwin_charmap_compare(dwin_charmap_t *v1, dwin_charmap_t *v2) {
+  return (v1->uchar < v2->uchar) ? -1 : (v1->uchar > v2->uchar) ? 1 : 0;
+}
+
+int pf_bsearch_cb_comp_dwinmap_pgm(void *userdata, size_t idx, void * data_pin) {
+  dwin_charmap_t localval;
+  dwin_charmap_t *p_dwin_charmap = (dwin_charmap_t *)userdata;
+  memcpy_P(&localval, p_dwin_charmap + idx, sizeof(localval));
+  return dwin_charmap_compare(&localval, (dwin_charmap_t *)data_pin);
+}
+
+DWIN_String dwin_string;
+
+#endif // IS_DWIN_MARLINUI

+ 1007 - 0
Marlin/src/lcd/e3v2/marlinui/dwin_string.h

@@ -0,0 +1,1007 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+
+
+#include "../../fontutils.h"
+#include "../../marlinui.h"
+
+typedef struct _dwin_charmap_t {
+  wchar_t uchar; // the unicode char
+  uint8_t idx;   // the glyph of the char in the ROM
+  uint8_t idx2;  // the char used to be combined with the idx to simulate a single char
+} dwin_charmap_t;
+
+#define MAX_STRING_LENGTH   64
+
+#define S(V) (char*)(V)
+
+class DWIN_String {
+  private:
+    //static glyph_t *glyphs[256];
+    //static font_t *font_header;
+
+    static uint8_t data[MAX_STRING_LENGTH + 1];
+    static uint16_t span;   // in pixels
+    static uint8_t len;  // in characters
+
+    static void add_character(uint8_t character);
+    static void eol() { data[len] = 0x00; }
+
+  public:
+    //static void set_font(const uint8_t *font);
+    //static void add_glyphs(const uint8_t *font);
+
+    //static font_t *font() { return font_header; };
+    //static uint16_t font_height() { return font_header->FontAscent - font_header->FontDescent; }
+    //static glyph_t *glyph(uint8_t character) { return glyphs[character] ?: glyphs[0x3F]; }  /* Use '?' for unknown glyphs */
+    //static inline glyph_t *glyph(uint8_t *character) { return glyph(*character); }
+
+    static void set();
+    //static void add(uint8_t character) { add_character(character); eol(); }
+    static void add(wchar_t character);
+    static void add(uint8_t *string, uint8_t max_len=MAX_STRING_LENGTH);
+    static void add(uint8_t *string, int8_t index, uint8_t *itemString=nullptr);
+    static void set(uint8_t *string)   { set(); add(string); }
+    static void set(wchar_t character) { set(); add(character); }
+    static void set(uint8_t *string, int8_t index, const char *itemString=nullptr) { set(); add(string, index, (uint8_t *)itemString); }
+    static inline void set(const __FlashStringHelper *fstring) { set((uint8_t *)fstring); }
+    static inline void set(const char *string) { set((uint8_t *)string); }
+    static inline void set(const char *string, int8_t index, const char *itemString=nullptr) { set((uint8_t *)string, index, itemString); }
+    static inline void add(const char *string) { add((uint8_t *)string); }
+
+    static void trim(uint8_t character=0x20);
+    static void rtrim(uint8_t character=0x20);
+    static void ltrim(uint8_t character=0x20);
+
+    static void truncate(uint8_t maxlen) { if (len > maxlen) { len = maxlen; eol(); } }
+
+    static uint8_t length() { return len; }
+    static uint16_t width() { return span; }
+    static uint8_t *string() { return data; }
+    static uint16_t center(uint16_t width) { return span > width ? 0 : (width - span) / 2; }
+};
+
+int dwin_charmap_compare(dwin_charmap_t *v1, dwin_charmap_t *v2);
+int pf_bsearch_cb_comp_dwinmap_pgm(void *userdata, size_t idx, void * data_pin);
+
+extern DWIN_String dwin_string;
+
+#ifdef __AVR__
+  #define IV(a) U##a
+#else
+  #define IV(a) L##a
+#endif
+
+const dwin_charmap_t g_dwin_charmap_device[] PROGMEM = {
+  // sorted by uchar:
+  #if DISPLAY_CHARSET_HD44780 == JAPANESE
+
+    {IV('¢'), 0xEC, 0}, // A2
+    {IV('°'), 0xDF, 0}, // B0, Marlin special: '°'  LCD_STR_DEGREE (0x09)
+    {IV('ä'), 0xE1, 0}, // E4
+    {IV('ö'), 0xEF, 0}, // F6
+    {IV('÷'), 0xFD, 0}, // 00F7
+    {IV('ü'), 0xF5, 0}, // 00FC
+    {IV('ˣ'), 0xEB, 0}, // 02E3
+
+    {IV('·'), 0xA5, 0}, // 0387
+    {IV('Ώ'), 0xF4, 0}, // 038F
+    {IV('Θ'), 0xF2, 0}, // 0398, Theta
+    {IV('Ξ'), 0xE3, 0}, // 039E, Xi
+    {IV('Σ'), 0xF6, 0}, // 03A3, Sigma
+    {IV('Ω'), 0xF4, 0}, // 03A9, Omega
+    {IV('ά'), 0xE0, 0}, // 03AC
+    {IV('έ'), 0xE3, 0}, // 03AD
+    {IV('α'), 0xE0, 0}, // 03B1, alpha
+    {IV('β'), 0xE2, 0}, // 03B2, beta
+    {IV('ε'), 0xE3, 0}, // 03B5, epsilon
+    {IV('θ'), 0xF2, 0}, // 03B8, theta
+    {IV('μ'), 0xE4, 0}, // 03BC, mu
+    {IV('ξ'), 0xE3, 0}, // 03BE, xi
+    {IV('π'), 0xF7, 0}, // 03C0, pi
+    {IV('ρ'), 0xE6, 0}, // 03C1, rho
+    {IV('σ'), 0xE5, 0}, // 03C3, sigma
+
+    {IV('←'), 0x7F, 0}, // 2190
+    {IV('→'), 0x7E, 0}, // 2192, Marlin special: '⮈⮉⮊⮋➤→' LCD_STR_ARROW_RIGHT (0x03)
+    {IV('√'), 0xE8, 0}, // 221A
+    {IV('∞'), 0xF3, 0}, // 221E
+    {IV('█'), 0xFF, 0}, // 2588
+
+    //{IV(''), 0xA0, 0},
+    {IV('。'), 0xA1, 0},
+    {IV('「'), 0xA2, 0},
+    {IV('」'), 0xA3, 0},
+    {IV('゛'), 0xDE, 0}, // ‶
+    {IV('゜'), 0xDF, 0}, // '〫'
+    {IV('゠'), '=', 0},
+    {IV('ァ'), 0xA7, 0},
+    {IV('ア'), 0xB1, 0},
+    {IV('ィ'), 0xA8, 0},
+    {IV('イ'), 0xB2, 0},
+    {IV('ゥ'), 0xA9, 0},
+    {IV('ウ'), 0xB3, 0},
+    {IV('ェ'), 0xAA, 0},
+    {IV('エ'), 0xB4, 0},
+    {IV('ォ'), 0xAB, 0},
+
+    {IV('オ'), 0xB5, 0},
+    {IV('カ'), 0xB6, 0},
+    {IV('ガ'), 0xB6, 0xDE},
+    {IV('キ'), 0xB7, 0},
+    {IV('ギ'), 0xB7, 0xDE},
+    {IV('ク'), 0xB8, 0},
+    {IV('グ'), 0xB8, 0xDE},
+    {IV('ケ'), 0xB9, 0},
+    {IV('ゲ'), 0xB9, 0xDE},
+    {IV('コ'), 0xBA, 0},
+    {IV('ゴ'), 0xBA, 0xDE},
+    {IV('サ'), 0xBB, 0},
+    {IV('ザ'), 0xBB, 0xDE},
+    {IV('シ'), 0xBC, 0},
+    {IV('ジ'), 0xBC, 0xDE},
+    {IV('ス'), 0xBD, 0},
+    {IV('ズ'), 0xBD, 0xDE},
+    {IV('セ'), 0xBE, 0},
+    {IV('ゼ'), 0xBE, 0xDE},
+    {IV('ソ'), 0xBF, 0},
+    {IV('ゾ'), 0xBF, 0xDE},
+
+    {IV('タ'), 0xC0, 0},
+    {IV('ダ'), 0xC0, 0xDE},
+    {IV('チ'), 0xC1, 0},
+    {IV('ヂ'), 0xC1, 0xDE},
+    {IV('ッ'), 0xAF, 0},
+    {IV('ツ'), 0xC2, 0},
+    {IV('ヅ'), 0xC2, 0xDE},
+    {IV('テ'), 0xC3, 0},
+    {IV('デ'), 0xC3, 0xDE},
+    {IV('ト'), 0xC4, 0},
+    {IV('ド'), 0xC4, 0xDE},
+    {IV('ナ'), 0xC5, 0},
+    {IV('ニ'), 0xC6, 0},
+    {IV('ヌ'), 0xC7, 0},
+    {IV('ネ'), 0xC8, 0},
+    {IV('ノ'), 0xC9, 0},
+    {IV('ハ'), 0xCA, 0},
+    {IV('バ'), 0xCA, 0xDE},
+    {IV('パ'), 0xCA, 0xDF},
+    {IV('ヒ'), 0xCB, 0},
+    {IV('ビ'), 0xCB, 0xDE},
+    {IV('ピ'), 0xCB, 0xDF},
+    {IV('フ'), 0xCC, 0},
+    {IV('ブ'), 0xCC, 0xDE},
+    {IV('プ'), 0xCC, 0xDF},
+    {IV('ヘ'), 0xCD, 0},
+    {IV('ベ'), 0xCD, 0xDE},
+    {IV('ペ'), 0xCD, 0xDF},
+    {IV('ホ'), 0xCE, 0},
+    {IV('ボ'), 0xCE, 0xDE},
+    {IV('ポ'), 0xCE, 0xDF},
+    {IV('マ'), 0xCF, 0},
+
+    {IV('ミ'), 0xD0, 0},
+    {IV('ム'), 0xD1, 0},
+    {IV('メ'), 0xD2, 0},
+    {IV('モ'), 0xD3, 0},
+    {IV('ャ'), 0xAC, 0},
+    {IV('ヤ'), 0xD4, 0},
+    {IV('ュ'), 0xAD, 0},
+    {IV('ユ'), 0xD5, 0},
+    {IV('ョ'), 0xAE, 0},
+    {IV('ヨ'), 0xD6, 0},
+    {IV('ラ'), 0xD7, 0},
+    {IV('リ'), 0xD8, 0},
+    {IV('ル'), 0xD9, 0},
+    {IV('レ'), 0xDA, 0},
+    {IV('ロ'), 0xDB, 0},
+    {IV('ワ'), 0xDC, 0},
+    {IV('ヲ'), 0xA6, 0},
+    {IV('ン'), 0xDD, 0},
+    {IV('ヴ'), 0xB3, 0xDE},
+    {IV('ヷ'), 0xDC, 0xDE},
+    {IV('ヺ'), 0xA6, 0xDE},
+    {IV('・'), 0xA5, 0},
+    {IV('ー'), 0xB0, 0},
+    {IV('ヽ'), 0xA4, 0},
+
+    //{IV('g'), 0xE7, 0}, // error
+    //{IV(''), 0xE9, 0},
+    //{IV('j'), 0xEA, 0}, // error
+    //{IV(''), 0xED, 0},
+    //{IV(''), 0xEE, 0},
+
+    //{IV('p'), 0xF0, 0}, // error
+    //{IV('q'), 0xF1, 0}, // error
+    //{IV(''), 0xF8, 0},
+    //{IV('y'), 0xF9, 0}, // error
+    {IV('万'), 0xFB, 0},
+    {IV('円'), 0xFC, 0},
+    {IV('千'), 0xFA, 0},
+    //{IV(''), 0xFE, 0},
+
+    //、・ヲァィゥェォャュョッー
+    {IV('、'), 0xA4, 0}, //ヽ
+    {IV('・'), 0xA5, 0}, //・
+    {IV('ヲ'), 0xA6, 0}, //ヲ
+    {IV('ァ'), 0xA7, 0}, //ァ
+    {IV('ィ'), 0xA8, 0}, //ィ
+    {IV('ゥ'), 0xA9, 0}, //ゥ
+    {IV('ェ'), 0xAA, 0}, //ェ
+    {IV('ォ'), 0xAB, 0}, //ォ
+    {IV('ャ'), 0xAC, 0}, //ャ
+    {IV('ュ'), 0xAD, 0}, //ュ
+    {IV('ョ'), 0xAE, 0}, //ョ
+    {IV('ッ'), 0xAF, 0}, //ッ
+    {IV('ー'), 0xB0, 0}, //ー
+
+    //アイウエオカキクケコサシスセ
+    {IV('ア'), 0xB1, 0}, //ア
+    {IV('イ'), 0xB2, 0}, //イ
+    {IV('ウ'), 0xB3, 0}, //ウ
+    {IV('エ'), 0xB4, 0}, //エ
+    {IV('オ'), 0xB5, 0}, //オ
+    {IV('カ'), 0xB6, 0}, //カ
+    {IV('キ'), 0xB7, 0}, //キ
+    {IV('ク'), 0xB8, 0}, //ク
+    {IV('ケ'), 0xB9, 0}, //ケ
+    {IV('コ'), 0xBA, 0}, //コ
+    {IV('サ'), 0xBB, 0}, //サ
+    {IV('シ'), 0xBC, 0}, //シ
+    {IV('ス'), 0xBD, 0}, //ス
+    {IV('セ'), 0xBE, 0}, //セ
+
+    //ソタチツテトナニヌネノハヒフ
+    {IV('ソ'), 0xBF, 0}, //ソ
+    {IV('タ'), 0xC0, 0}, //タ
+    {IV('チ'), 0xC1, 0}, //チ
+    {IV('ツ'), 0xC2, 0}, //ツ
+    {IV('テ'), 0xC3, 0}, //テ
+    {IV('ト'), 0xC4, 0}, //ト
+    {IV('ナ'), 0xC5, 0}, //ナ
+    {IV('ニ'), 0xC6, 0}, //ニ
+    {IV('ヌ'), 0xC7, 0}, //ヌ
+    {IV('ネ'), 0xC8, 0}, //ネ
+    {IV('ノ'), 0xC9, 0}, //ノ
+    {IV('ハ'), 0xCA, 0}, //ハ
+    {IV('ヒ'), 0xCB, 0}, //ヒ
+    {IV('フ'), 0xCC, 0}, //フ
+
+    //ヘホマミムメモヤユヨラリルレロワン゙゚
+    {IV('ヘ'), 0xCD, 0}, //ヘ
+    {IV('ホ'), 0xCE, 0}, //ホ
+    {IV('マ'), 0xCF, 0}, //マ
+    {IV('ミ'), 0xD0, 0}, //ミ
+    {IV('ム'), 0xD1, 0}, //ム
+    {IV('メ'), 0xD2, 0}, //メ
+    {IV('モ'), 0xD3, 0}, //モ
+    {IV('ヤ'), 0xD4, 0}, //ヤ
+    {IV('ユ'), 0xD5, 0}, //ユ
+    {IV('ヨ'), 0xD6, 0}, //ヨ
+    {IV('ラ'), 0xD7, 0}, //ラ
+    {IV('リ'), 0xD8, 0}, //リ
+    {IV('ル'), 0xD9, 0}, //ル
+    {IV('レ'), 0xDA, 0}, //レ
+    {IV('ロ'), 0xDB, 0}, //ロ
+    {IV('ワ'), 0xDC, 0}, //ワ
+    {IV('ン'), 0xDD, 0}, //ン
+    {IV('゙'), 0xDE, 0}, // ゛
+    {IV('゚'), 0xDF, 0}, // ゜
+
+    {IV('¥'), 0x5C, 0},
+
+  #elif DISPLAY_CHARSET_HD44780 == WESTERN
+    // 0x10 -- 0x1F (except 0x1C)
+    // 0x80 -- 0xFF (except 0xA7,0xB0,0xB1,0xB3,0xB4,0xBF,0xD1,0xF8,0xFA,0xFC-0xFF)
+
+    {IV('¡'), 0xA9, 0},
+    {IV('¢'), 0xA4, 0},
+    {IV('£'), 0xA5, 0},
+    {IV('¥'), 0xA6, 0},
+    {IV('§'), 0xD2, 0}, // section sign
+    {IV('©'), 0xCF, 0},
+
+    {IV('ª'), 0x9D, 0},
+    {IV('«'), 0xBB, 0},
+    {IV('®'), 0xCE, 0},
+
+    {IV('°'), 0xB2, 0}, // Marlin special: '°'  LCD_STR_DEGREE (0x09)
+    //{IV(''), 0xD1, 0},
+    {IV('±'), 0x10, 0}, //∓±
+    //{'='), 0x1C, 0}, // error
+    {IV('²'), 0x1E, 0},
+    {IV('³'), 0x1F, 0},
+    {IV('¶'), 0xD3, 0}, // pilcrow sign
+    {IV('º'), 0x9E, 0},
+    {IV('»'), 0xBC, 0}, // 00BB
+    //{IV(''), 0xB3, 0}, // error
+    //{IV(''), 0xB4, 0}, // error
+    {IV('¼'), 0xB6, 0}, // 00BC
+    {IV('½'), 0xB5, 0}, // 00BD
+    //{IV('¾'), '3', 0}, // 00BE
+    {IV('¿'), 0x9F, 0}, // 00BF
+
+    {IV('Â'), 0x8F, 0},
+    {IV('Ã'), 0xAA, 0},
+    {IV('Ä'), 0x8E, 0},
+    {IV('Æ'), 0x92, 0},
+    {IV('Ç'), 0x80, 0},
+    {IV('É'), 0x90, 0},
+    {IV('Ñ'), 0x9C, 0},
+    {IV('Õ'), 0xAC, 0},
+    {IV('Ö'), 0x99, 0},
+    {IV('×'), 0xB7, 0},
+    {IV('Ø'), 0xAE, 0},
+    {IV('Ü'), 0x9A, 0},
+    {IV('à'), 0x85, 0},
+    {IV('á'), 0xA0, 0},
+    {IV('â'), 0x83, 0},
+    {IV('ã'), 0xAB, 0},
+    {IV('ä'), 0x84, 0},
+    {IV('å'), 0x86, 0},
+    {IV('æ'), 0x91, 0},
+    {IV('ç'), 0x87, 0},
+    {IV('è'), 0x8A, 0},
+    {IV('é'), 0x82, 0},
+    {IV('ê'), 0x88, 0},
+    {IV('ë'), 0x89, 0},
+    {IV('ì'), 0x8D, 0},
+    {IV('í'), 0xA1, 0},
+    {IV('î'), 0x8C, 0},
+    {IV('ï'), 0x8B, 0},
+
+    {IV('ñ'), 0x9B, 0},
+    {IV('ò'), 0x95, 0},
+    {IV('ó'), 0xA2, 0},
+    {IV('ô'), 0x93, 0},
+    {IV('õ'), 0xAD, 0},
+    {IV('ö'), 0x94, 0},
+    {IV('÷'), 0xB8, 0},
+    {IV('ø'), 0xAF, 0},
+    {IV('ù'), 0x97, 0},
+    {IV('ú'), 0xA3, 0},
+    {IV('û'), 0x96, 0},
+    {IV('ü'), 0x81, 0},
+    {IV('ÿ'), 0x98, 0},
+
+    //{IV(''), 0xB0, 0}, // error
+    //{IV(''), 0xB1, 0}, // error
+    {IV('ƒ'), 0xA8, 0}, // 0192
+
+    {IV('Ύ'), 0xDB, 0}, // 038E
+    {IV('Ώ'), 0xDE, 0}, // 038F
+    {IV('ΐ'), 0xE7, 0}, // 0390
+
+    {IV('Γ'), 0xD4, 0}, // 0393, Gamma
+    {IV('Δ'), 0xD5, 0}, // 0394, Delta, ◿
+    {IV('Θ'), 0xD6, 0}, // 0398, Theta
+    {IV('Λ'), 0xD7, 0}, // 039B, Lambda
+    {IV('Ξ'), 0xD8, 0}, // 039E, Xi
+    {IV('Π'), 0xD9, 0}, // Pi
+    {IV('Σ'), 0xDA, 0}, // Sigma
+    {IV('Υ'), 0xDB, 0}, // Upsilon
+    {IV('Φ'), 0xDC, 0}, // Phi
+    {IV('Ψ'), 0xDD, 0}, // Psi
+    {IV('Ω'), 0xDE, 0}, // Omega
+
+    {IV('ά'), 0xDF, 0}, // 03AC
+    {IV('έ'), 0xE3, 0}, // 03AD
+    {IV('ή'), 0xE5, 0}, // 03AE
+    {IV('ί'), 0xE7, 0}, // 03AF
+    {IV('ΰ'), 0xF1, 0}, // 03B0
+
+    {IV('α'), 0xDF, 0}, // alpha
+    {IV('β'), 0xE0, 0}, // beta
+    {IV('γ'), 0xE1, 0}, // gamma
+    {IV('δ'), 0xE2, 0}, // delta
+    {IV('ε'), 0xE3, 0}, // epsilon
+    {IV('ζ'), 0xE4, 0}, // zeta
+    {IV('η'), 0xE5, 0}, // eta
+    {IV('θ'), 0xE6, 0}, // theta
+    {IV('ι'), 0xE7, 0}, // lota
+    {IV('κ'), 0xE8, 0}, // kappa
+    {IV('λ'), 0xE9, 0}, // lambda
+    {IV('μ'), 0xEA, 0}, // mu
+    {IV('ν'), 0xEB, 0}, // nu
+    {IV('ξ'), 0xEC, 0}, // xi
+    {IV('π'), 0xED, 0}, // pi
+    {IV('ρ'), 0xEE, 0}, // rho
+    {IV('σ'), 0xEF, 0}, // sigma
+
+    {IV('τ'), 0xF0, 0}, // tau
+    {IV('υ'), 0xF1, 0}, // upsilon
+    {IV('χ'), 0xF2, 0}, // chi
+    {IV('ψ'), 0xF3, 0}, // psi
+    {IV('ω'), 0xF4, 0}, // 03C9, omega
+    {IV('ϊ'), 0xE7, 0}, // 03CA
+    {IV('ϋ'), 0xF1, 0}, // 03CB
+    {IV('ύ'), 0xF1, 0}, // 03CD
+    {IV('ώ'), 0xF4, 0}, // 03CE
+
+    {IV('•'), 0xCD, 0}, // ·
+    {IV('℞'), 0xA7, 0}, // ℞ Pt ASCII 158
+    {IV('™'), 0xD0, 0},
+    {IV('↤'), 0xF9, 0}, // ⟻
+    {IV('↵'), 0xC4, 0},
+    {IV('↻'), 0x04, 0}, // Marlin special: '↻↺⟳⟲'  LCD_STR_REFRESH (0x01)
+    {IV('⇥'), 0xFB, 0},
+    {IV('√'), 0xBE, 0}, // √
+    {IV('∞'), 0xC2, 0}, // infinity
+    {IV('∫'), 0x1B, 0},
+    {IV('∼'), 0x1D, 0},
+    {IV('≈'), 0x1A, 0},
+    {IV('≠'), 0xBD, 0},
+    {IV('≡'), 0x11, 0},
+    {IV('≤'), 0xB9, 0},// ≤≥ ⩽⩾
+    {IV('≥'), 0xBA, 0},
+    //{IV(''), 0xBF, 0}, // error
+
+    {IV('⌠'), 0xC0, 0},
+    {IV('⌡'), 0xC1, 0},
+
+    {IV('⎧'), 0x14, 0},
+    {IV('⎩'), 0x15, 0},
+    {IV('⎫'), 0x16, 0},
+    {IV('⎭'), 0x17, 0},
+    {IV('⎰'), 0x18, 0},
+    {IV('⎱'), 0x19, 0},
+
+    {IV('⎲'), 0x12, 0},
+    {IV('⎳'), 0x13, 0},
+
+    {IV('⏱'), 0x07, 0}, // Marlin special: '🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜🕝🕞🕟🕠🕡🕢🕣🕤🕥🕦🕧 ⌚⌛⏰⏱⏳⧖⧗'  LCD_STR_CLOCK (0x05)
+    {IV('┌'), 0xC9, 0},
+    {IV('┐'), 0xCA, 0},
+    {IV('└'), 0xCB, 0},
+    {IV('┘'), 0xCC, 0},
+    {IV('◸'), 0xC3, 0}, // ◿
+    {IV('⭠'), 0xC8, 0},
+    {IV('⭡'), 0xC5, 0},
+    {IV('⭢'), 0xC7, 0},
+    {IV('⭣'), 0xC6, 0},
+
+
+    {IV('⯆'), 0xF5, 0},
+    {IV('⯇'), 0xF7, 0}, // ⯅
+    {IV('⯈'), 0xF6, 0},
+    //{IV(''), 0xF8, 0}, // error
+    //{IV(''), 0xFA, 0}, // error
+    //{IV(''), 0xFC, 0}, // error
+    //{IV(''), 0xFD, 0}, // error
+    //{IV(''), 0xFE, 0}, // error
+    //{IV(''), 0xFF, 0}, // error
+
+  #elif DISPLAY_CHARSET_HD44780 == CYRILLIC
+
+    {IV('¢'), 0x5C, 0}, // 00A2
+    {IV('£'), 0xCF, 0}, // 00A3
+    {IV('°'), 0x01, 0}, // 00B0, Marlin special: '°'  LCD_STR_DEGREE (0x09)
+
+    //{IV(''), 0x80, 0},
+    //{IV(''), 0x81, 0},
+    //{IV(''), 0x82, 0},
+    //{IV(''), 0x83, 0},
+    //{IV(''), 0x84, 0},
+    //{IV(''), 0x85, 0},
+    //{IV(''), 0x86, 0},
+    //{IV(''), 0x87, 0},
+    //{IV(''), 0x88, 0},
+    //{IV(''), 0x89, 0},
+    //{IV(''), 0x8A, 0},
+    //{IV(''), 0x8B, 0},
+    //{IV(''), 0x8C, 0},
+    //{IV(''), 0x8D, 0},
+    //{IV(''), 0x8E, 0},
+    //{IV(''), 0x8F, 0},
+
+    //{IV(''), 0x90, 0},
+    //{IV(''), 0x91, 0},
+    //{IV(''), 0x92, 0},
+    //{IV(''), 0x93, 0},
+    //{IV(''), 0x94, 0},
+    //{IV(''), 0x95, 0},
+    //{IV(''), 0x96, 0},
+    //{IV(''), 0x97, 0},
+    //{IV(''), 0x98, 0},
+    //{IV(''), 0x99, 0},
+    //{IV(''), 0x9A, 0},
+    //{IV(''), 0x9B, 0},
+    //{IV(''), 0x9C, 0},
+    //{IV(''), 0x9D, 0},
+    //{IV(''), 0x9E, 0},
+    //{IV(''), 0x9F, 0},
+
+
+    {IV('¼'), 0xF0, 0}, // 00BC
+    {IV('⅓'), 0xF1, 0},
+    {IV('½'), 0xF2, 0}, // 00BD
+    {IV('¾'), 0xF3, 0}, // 00BE
+    {IV('¿'), 0xCD, 0}, // 00BF
+
+    #if ENABLED(DISPLAY_CHARSET_ISO10646_5)
+
+      // Map Cyrillic to HD44780 extended CYRILLIC where possible
+      {IV('Ё'), 0xA2, 0}, // 0401
+      {IV('А'), 'A', 0}, // 0410
+      {IV('Б'), 0xA0, 0},
+      {IV('В'), 'B', 0},
+      {IV('Г'), 0xA1, 0},
+      {IV('Д'), 0xE0, 0},
+      {IV('Е'), 'E', 0},
+      {IV('Ж'), 0xA3, 0},
+      {IV('З'), 0xA4, 0},
+      {IV('И'), 0xA5, 0},
+      {IV('Й'), 0xA6, 0},
+      {IV('К'), 'K', 0},
+      {IV('Л'), 0xA7, 0},
+      {IV('М'), 'M', 0},
+      {IV('Н'), 'H', 0},
+      {IV('О'), 'O', 0},
+      {IV('П'), 0xA8, 0},
+      {IV('Р'), 'P', 0},
+      {IV('С'), 'C', 0},
+      {IV('Т'), 'T', 0},
+      {IV('У'), 0xA9, 0},
+      {IV('Ф'), 0xAA, 0},
+      {IV('Х'), 'X', 0},
+      {IV('Ц'), 0xE1, 0},
+      {IV('Ч'), 0xAB, 0},
+      {IV('Ш'), 0xAC, 0},
+      {IV('Щ'), 0xE2, 0},
+      {IV('Ъ'), 0xAD, 0},
+      {IV('Ы'), 0xAE, 0},
+      {IV('Ь'), 'b', 0},
+      {IV('Э'), 0xAF, 0},
+      {IV('Ю'), 0xB0, 0},
+      {IV('Я'), 0xB1, 0},
+      {IV('а'), 'a', 0},
+
+      {IV('б'), 0xB2, 0},
+      {IV('в'), 0xB3, 0},
+      {IV('г'), 0xB4, 0},
+      {IV('д'), 0xE3, 0},
+      {IV('е'), 'e', 0},
+      {IV('ж'), 0xB6, 0},
+      {IV('з'), 0xB7, 0},
+      {IV('и'), 0xB8, 0},
+      {IV('й'), 0xB9, 0},
+      {IV('к'), 0xBA, 0}, //клмноп
+      {IV('л'), 0xBB, 0},
+      {IV('м'), 0xBC, 0},
+      {IV('н'), 0xBD, 0},
+      {IV('о'), 'o', 0},
+      {IV('п'), 0xBE, 0},
+      {IV('р'), 'p', 0},
+      {IV('с'), 'c', 0},
+      {IV('т'), 0xBF, 0},
+
+      {IV('у'), 'y', 0},
+      {IV('ф'), 0xE4, 0},
+      {IV('х'), 'x', 0},
+      {IV('ц'), 0xE5, 0},
+      {IV('ч'), 0xC0, 0},
+      {IV('ш'), 0xC1, 0},
+      {IV('щ'), 0xE6, 0},
+      {IV('ъ'), 0xC2, 0},
+      {IV('ы'), 0xC3, 0},
+      {IV('ь'), 0xC4, 0},
+      {IV('э'), 0xC5, 0},
+      {IV('ю'), 0xC6, 0},
+      {IV('я'), 0xC7, 0}, // 044F
+      {IV('ё'), 0xB5, 0}, // 0451
+      //{IV(''), 0xC8, 0},
+      //{IV(''), 0xC9, 0},
+      //{IV(''), 0xCA, 0},
+      //{IV(''), 0xCB, 0},
+      //{IV(''), 0xCC, 0},
+      //{IV(''), 0xCD, 0},
+      //{IV(''), 0xCE, 0},
+
+      //{IV(''), 0xD0, 0},
+      //{IV(''), 0xD1, 0},
+      //{IV(''), 0xD2, 0},
+      //{IV(''), 0xD3, 0},
+      //{IV(''), 0xD4, 0},
+      //{IV(''), 0xD5, 0},
+      //{IV(''), 0xD6, 0},
+      //{IV(''), 0xD7, 0},
+      //{IV(''), 0xD8, 0},
+      //{IV(''), 0xDB, 0},
+      //{IV(''), 0xDC, 0},
+      //{IV(''), 0xDD, 0},
+      //{IV(''), 0xDE, 0},
+      //{IV(''), 0xDF, 0},
+
+      //{IV(''), 0xE7, 0},
+      //{IV(''), 0xE8, 0},
+      //{IV(''), 0xE9, 0},
+      //{IV(''), 0xEA, 0},
+      //{IV(''), 0xEB, 0},
+      //{IV(''), 0xEC, 0},
+      //{IV(''), 0xED, 0},
+      //{IV(''), 0xEE, 0},
+      //{IV(''), 0xEF, 0},
+
+      //{IV(''), 0xF4, 0},
+      //{IV(''), 0xF5, 0},
+      //{IV(''), 0xF6, 0},
+      //{IV(''), 0xF7, 0},
+      //{IV(''), 0xF8, 0},
+      //{IV(''), 0xF9, 0},
+      //{IV(''), 0xFA, 0},
+      //{IV(''), 0xFB, 0},
+      //{IV(''), 0xFC, 0},
+      //{IV(''), 0xFD, 0},
+      //{IV(''), 0xFE, 0},
+      //{IV(''), 0xFF, 0},
+
+    #endif
+
+    {IV('↑'), 0xD9, 0}, // 2191 ←↑→↓
+    {IV('↓'), 0xDA, 0}, // 2193
+  #endif
+};
+
+// the plain ASCII replacement for various char
+const dwin_charmap_t g_dwin_charmap_common[] PROGMEM = {
+  {IV('¡'), 'i', 0}, // A1
+  {IV('¢'), 'c', 0}, // A2
+  {IV('°'), 0x09, 0}, // B0 Marlin special: '°'  LCD_STR_DEGREE (0x09)
+
+  // Map WESTERN code to plain ASCII
+  {IV('Á'), 'A', 0}, // C1
+  {IV('Â'), 'A', 0}, // C2
+  {IV('Ã'), 'A', 0}, // C3
+  {IV('Ä'), 'A', 0}, // C4
+  {IV('Å'), 'A', 0}, // C5
+  {IV('Æ'), 'A', 'E'}, // C6
+  {IV('Ç'), 'C', 0}, // C7
+  {IV('È'), 'E', 0}, // C8
+  {IV('É'), 'E', 0}, // C9
+  {IV('Í'), 'I', 0}, // CD
+  {IV('Ñ'), 'N', 0}, // D1
+  {IV('Õ'), 'O', 0}, // D5
+  {IV('Ö'), 'O', 0}, // D6
+  {IV('×'), 'x', 0}, // D7
+  {IV('Ü'), 'U', 0}, // DC
+  {IV('Ý'), 'Y', 0}, // DD
+  {IV('à'), 'a', 0}, // E0
+  {IV('á'), 'a', 0},
+  {IV('â'), 'a', 0},
+  {IV('ã'), 'a', 0},
+  {IV('ä'), 'a', 0},
+  {IV('å'), 'a', 0},
+  {IV('æ'), 'a', 'e'},
+  {IV('ç'), 'c', 0},
+  {IV('è'), 'e', 0}, // 00E8
+  {IV('é'), 'e', 0},
+  {IV('ê'), 'e', 0},
+  {IV('ë'), 'e', 0},
+  {IV('ì'), 'i', 0}, // 00EC
+  {IV('í'), 'i', 0},
+  {IV('î'), 'i', 0},
+  {IV('ï'), 'i', 0}, // 00EF
+
+  {IV('ñ'), 'n', 0}, // 00F1
+  {IV('ò'), 'o', 0},
+  {IV('ó'), 'o', 0},
+  {IV('ô'), 'o', 0},
+  {IV('õ'), 'o', 0},
+  {IV('ö'), 'o', 0},
+  //{IV('÷'), 0xB8, 0},
+  {IV('ø'), 'o', 0},
+  {IV('ù'), 'u', 0},
+  {IV('ú'), 'u', 0},
+  {IV('û'), 'u', 0},
+  {IV('ü'), 'u', 0}, // FC
+  {IV('ý'), 'y', 0}, // FD
+  {IV('ÿ'), 'y', 0}, // FF
+
+  {IV('Ą'), 'A', 0}, // 0104
+  {IV('ą'), 'a', 0}, // 0105
+  {IV('Ć'), 'C', 0}, // 0106
+  {IV('ć'), 'c', 0}, // 0107
+  {IV('Č'), 'C', 0}, // 010C
+  {IV('č'), 'c', 0}, // 010D
+  {IV('Ď'), 'D', 0}, // 010E
+  {IV('ď'), 'd', 0}, // 010F
+  {IV('đ'), 'd', 0}, // 0111
+  {IV('ę'), 'e', 0}, // 0119
+  {IV('Ě'), 'E', 0}, // 011A
+  {IV('ě'), 'e', 0}, // 011B
+  {IV('ğ'), 'g', 0}, // 011F
+  {IV('İ'), 'I', 0}, // 0130
+  {IV('ı'), 'i', 0}, // 0131
+
+  {IV('Ł'), 'L', 0}, // 0141
+  {IV('ł'), 'l', 0}, // 0142
+  {IV('Ń'), 'N', 0}, // 0143
+  {IV('ń'), 'n', 0}, // 0144
+  {IV('ň'), 'n', 0}, // 0148
+
+  {IV('Ř'), 'R', 0}, // 0158
+  {IV('ř'), 'r', 0}, // 0159
+  {IV('Ś'), 'S', 0}, // 015A
+  {IV('ś'), 's', 0}, // 015B
+  {IV('ş'), 's', 0}, // 015F
+  {IV('Š'), 'S', 0}, // 0160
+  {IV('š'), 's', 0}, // 0161
+  {IV('ť'), 't', 0}, // 0165
+  {IV('ů'), 'u', 0}, // 016F
+  {IV('ż'), 'z', 0}, // 017C
+  {IV('Ž'), 'Z', 0}, // 017D
+  {IV('ž'), 'z', 0}, // 017E
+  {IV('ƒ'), 'f', 0}, // 0192
+
+  {IV('ˣ'), 'x', 0}, // 02E3
+
+  #if ENABLED(DISPLAY_CHARSET_ISO10646_VI)
+
+    // Map Vietnamese phonetics
+
+    //{IV('à'), 'a', 0}, {IV('À'), 'A', 0},
+    {IV('ạ'), 'a', 0}, {IV('Ạ'), 'A', 0},
+    {IV('ả'), 'a', 0}, {IV('Ả'), 'A', 0},
+    //{IV('ã'), 'a', 0}, {IV('Ã'), 'A', 0},
+    //{IV('á'), 'á', 0}, {IV('Á'), 'A', 0},
+    {IV('Ạ'), 'A', 0},
+    {IV('ă'), 'a', 0}, {IV('Ă'), 'A', 0},
+    {IV('ằ'), 'a', 0}, {IV('Ằ'), 'A', 0},
+    {IV('ẳ'), 'a', 0}, {IV('Ẳ'), 'A', 0},
+    {IV('ẵ'), 'a', 0}, {IV('Ẵ'), 'A', 0},
+    {IV('ắ'), 'a', 0}, {IV('Ắ'), 'A', 0},
+    {IV('ặ'), 'a', 0}, {IV('Ặ'), 'A', 0},
+    {IV('â'), 'a', 0}, {IV('Â'), 'A', 0},
+    {IV('ầ'), 'a', 0}, {IV('Ầ'), 'A', 0},
+    {IV('ẩ'), 'a', 0}, {IV('Ẩ'), 'A', 0},
+    {IV('ẫ'), 'a', 0}, {IV('Ẫ'), 'A', 0},
+    {IV('ấ'), 'a', 0}, {IV('Ấ'), 'A', 0},
+    {IV('ậ'), 'a', 0}, {IV('Ậ'), 'A', 0},
+    //{IV('đ'), 'd', 0},
+                       {IV('Đ'), 'D', 0},
+    {IV('e'), 'e', 0}, {IV('E'), 'E', 0},
+    {IV('è'), 'e', 0}, {IV('È'), 'E', 0},
+    {IV('ẻ'), 'e', 0}, {IV('Ẻ'), 'E', 0},
+    {IV('ẽ'), 'e', 0}, {IV('Ẽ'), 'E', 0},
+    {IV('é'), 'e', 0}, {IV('É'), 'E', 0},
+    {IV('ẹ'), 'e', 0}, {IV('Ẹ'), 'E', 0},
+    {IV('ê'), 'e', 0}, {IV('Ê'), 'E', 0},
+    {IV('ề'), 'e', 0}, {IV('Ề'), 'E', 0},
+    {IV('ể'), 'e', 0}, {IV('Ể'), 'E', 0},
+    {IV('ễ'), 'e', 0}, {IV('Ễ'), 'E', 0},
+    {IV('ế'), 'e', 0}, {IV('Ế'), 'E', 0},
+    {IV('ệ'), 'e', 0}, {IV('Ệ'), 'E', 0},
+    {IV('i'), 'i', 0}, {IV('I'), 'I', 0},
+    //{IV('ì'), 'ì', 0}, {IV('Ì'), 'Ì', 0},
+    {IV('ỉ'), 'ỉ', 0}, {IV('Ỉ'), 'Ỉ', 0},
+    {IV('ĩ'), 'ĩ', 0}, {IV('Ĩ'), 'Ĩ', 0},
+    {IV('í'), 'í', 0}, {IV('Í'), 'Í', 0},
+    {IV('ị'), 'ị', 0}, {IV('Ị'), 'Ị', 0},
+    {IV('o'), 'o', 0}, {IV('O'), 'O', 0},
+    {IV('ò'), 'o', 0}, {IV('Ò'), 'O', 0},
+    {IV('ỏ'), 'o', 0}, {IV('Ỏ'), 'O', 0},
+    {IV('õ'), 'o', 0}, {IV('Õ'), 'O', 0},
+    {IV('ó'), 'o', 0}, {IV('Ó'), 'O', 0},
+    {IV('ọ'), 'o', 0}, {IV('Ọ'), 'O', 0},
+    {IV('ô'), 'o', 0}, {IV('Ô'), 'O', 0},
+    {IV('ồ'), 'o', 0}, {IV('Ồ'), 'O', 0},
+    {IV('ổ'), 'o', 0}, {IV('Ổ'), 'O', 0},
+    {IV('ỗ'), 'o', 0}, {IV('Ỗ'), 'O', 0},
+    {IV('ố'), 'o', 0}, {IV('Ố'), 'O', 0},
+    {IV('ộ'), 'o', 0}, {IV('Ộ'), 'O', 0},
+    {IV('ơ'), 'o', 0}, {IV('Ơ'), 'O', 0},
+    {IV('ờ'), 'o', 0}, {IV('Ờ'), 'O', 0},
+    {IV('ở'), 'o', 0}, {IV('Ở'), 'O', 0},
+    {IV('ỡ'), 'o', 0}, {IV('Ỡ'), 'O', 0},
+    {IV('ớ'), 'o', 0}, {IV('Ớ'), 'O', 0},
+    {IV('ợ'), 'o', 0}, {IV('Ợ'), 'O', 0},
+    {IV('ù'), 'u', 0}, {IV('Ù'), 'U', 0},
+    {IV('ủ'), 'u', 0}, {IV('Ủ'), 'U', 0},
+    {IV('ũ'), 'u', 0}, {IV('Ũ'), 'U', 0},
+    //{IV('ú'), 'u', 0}, {IV('Ú'), 'U', 0},
+    {IV('ụ'), 'u', 0}, {IV('Ụ'), 'U', 0},
+    {IV('ư'), 'u', 0}, {IV('Ư'), 'U', 0},
+    {IV('ừ'), 'u', 0}, {IV('Ừ'), 'U', 0},
+    {IV('ử'), 'u', 0}, {IV('Ử'), 'U', 0},
+    {IV('ữ'), 'u', 0}, {IV('Ữ'), 'U', 0},
+    {IV('ứ'), 'u', 0}, {IV('Ứ'), 'U', 0},
+    {IV('ự'), 'u', 0}, {IV('Ự'), 'U', 0},
+    {IV('y'), 'y', 0}, {IV('Y'), 'Y', 0},
+
+  #endif
+
+  #if ENABLED(DISPLAY_CHARSET_ISO10646_GREEK)
+
+    {IV('΄'), '\'', 0}, // 0384
+    {IV('΅'), '\'', 0}, // 0385
+    {IV('Ά'), 'A', 0}, // 0386
+    {IV('·'), '.', 0}, // 0387
+    {IV('Έ'), 'E', 0}, // 0388
+    {IV('Ή'), 'H', 0}, // 0389
+    {IV('Ί'), 'I', 0}, // 038A
+    {IV('Ό'), 'O', 0}, // 038C
+    {IV('Ύ'), 'Y', 0}, // 038E
+    {IV('Ώ'), 'O', 0}, // 038F
+    {IV('ΐ'), 'i', 0}, // 0390
+    {IV('Α'), 'A', 0}, // 0391
+    {IV('Β'), 'B', 0}, // 0392
+    {IV('Γ'), 'T', 0}, // 0393, Gamma
+    {IV('Δ'), '4', 0}, // 0394, Delta, ◿
+    {IV('Ε'), 'E', 0}, // 0395
+    {IV('Ζ'), 'Z', 0}, // 0396
+    {IV('Η'), 'H', 0}, // 0397
+    {IV('Θ'), '0', 0}, // 0398, Theta
+    {IV('Ι'), 'I', 0}, // 0399
+    {IV('Κ'), 'K', 0}, // 039A
+    {IV('Λ'), '^', 0}, // 039B, Lambda
+    {IV('Μ'), 'M', 0}, // 039C
+    {IV('Ν'), 'N', 0}, // 039D
+    {IV('Ξ'), '3', 0}, // 039E, Xi
+    {IV('Ο'), 'O', 0}, // 039F
+    {IV('Π'), 'n', 0}, // 03A0, Pi
+    {IV('Ρ'), 'P', 0}, // 03A1
+    {IV('Σ'), 'E', 0}, // 03A3, Sigma
+    {IV('Τ'), 'T', 0}, // 03A4
+    {IV('Υ'), 'Y', 0}, // 03A5, Upsilon
+    {IV('Φ'), 'p', 0}, // 03A6, Phi
+    {IV('Χ'), 'X', 0}, // 03A7
+    {IV('Ψ'), 'P', 0}, // 03A8, Psi
+    {IV('Ω'), 'O', 0}, // 03A9, Omega
+    {IV('Ϊ'), 'I', 0}, // 03AA
+    {IV('Ϋ'), 'Y', 0}, // 03AB
+    {IV('ά'), 'a', 0}, // 03AC
+    {IV('έ'), 'e', 0}, // 03AD
+    {IV('ή'), 'n', 0}, // 03AE
+    {IV('ί'), 'i', 0}, // 03AF
+    {IV('ΰ'), 'v', 0}, // 03B0
+    {IV('α'), 'a', 0}, // 03B1, alpha
+    {IV('β'), 'B', 0}, // 03B2, beta
+    {IV('γ'), 'v', 0}, // 03B3, gamma
+    {IV('δ'), 'd', 0}, // 03B4, delta
+    {IV('ε'), 'e', 0}, // 03B5, epsilon
+    {IV('ζ'), 'Z', 0}, // 03B6, zeta
+    {IV('η'), 'n', 0}, // 03B7, eta
+    {IV('θ'), '0', 0}, // 03B8, theta
+    {IV('ι'), 'i', 0}, // 03B9, lota
+    {IV('κ'), 'k', 0}, // 03BA, kappa
+    {IV('λ'), 'L', 0}, // 03BB, lambda
+    {IV('μ'), 'u', 0}, // 03BC, mu
+    {IV('ν'), 'v', 0}, // 03BD, nu
+    {IV('ξ'), 'e', 0}, // 03BE, xi
+    {IV('ο'), 'o', 0}, // 03BF
+    {IV('π'), 'n', 0}, // 03C0, pi
+    {IV('ρ'), 'p', 0}, // 03C1, rho
+    {IV('ς'), 'c', 0}, // 03C2
+    {IV('σ'), 'o', 0}, // 03C3, sigma
+    {IV('τ'), 't', 0}, // 03C4, tau
+    {IV('υ'), 'v', 0}, // 03C5, upsilon
+    {IV('φ'), 'p', 0}, // 03C6
+    {IV('χ'), 'X', 0}, // 03C7, chi
+    {IV('ψ'), 'W', 0}, // 03C8, psi
+    {IV('ω'), 'w', 0}, // 03C9, omega
+    {IV('ϊ'), 'i', 0}, // 03CA
+    {IV('ϋ'), 'v', 0}, // 03CB
+    {IV('ό'), 'o', 0}, // 03CC
+    {IV('ύ'), 'v', 0}, // 03CD
+    {IV('ώ'), 'w', 0}, // 03CE
+
+  #endif
+
+  #if ENABLED(DISPLAY_CHARSET_ISO10646_5)
+    // Map CYRILLIC code to plain ASCII
+    {IV('Ё'), 'E', 0}, // 0401
+    {IV('А'), 'A', 0}, // 0410
+    {IV('Б'), 'b', 0}, // 0411
+    {IV('В'), 'B', 0}, // 0412
+    {IV('Г'), 'T', 0}, // 0413
+    {IV('Д'), 'Q', 0}, // 0414
+    {IV('Е'), 'E', 0}, // 0415
+    {IV('Ж'), '*', 0}, // 0416
+    {IV('З'), 'E', 0}, // 0417
+    {IV('И'), 'N', 0}, // 0418
+    {IV('Й'), 'N', 0}, // 0419
+    {IV('К'), 'K', 0}, // 041A
+    {IV('Л'), 'T', 0}, // 041B
+    {IV('М'), 'M', 0}, // 041C
+    {IV('Н'), 'H', 0}, // 041D
+    {IV('О'), 'O', 0}, // 041E
+    {IV('П'), 'n', 0}, // 041F
+    {IV('Р'), 'P', 0}, // 0420
+    {IV('С'), 'C', 0}, // 0421
+    {IV('Т'), 'T', 0}, // 0422
+    {IV('У'), 'Y', 0},
+    {IV('Ф'), 'o', 0},
+    {IV('Х'), 'X', 0},
+    {IV('Ц'), 'U', 0},
+    {IV('Ч'), 'y', 0},
+    {IV('Ш'), 'W', 0},
+    {IV('Щ'), 'W', 0},
+    {IV('Ъ'), 'b', 0},
+    {IV('Ы'), 'b', '|'},
+    {IV('Ь'), 'b'},
+    {IV('Э'), 'e'},
+    {IV('Ю'), '|', 'O'},
+    {IV('Я'), '9', '|'}, // 042F
+
+    {IV('а'), 'a', 0}, // 0430
+    {IV('б'), '6', 0}, // 0431
+    {IV('в'), 'B', 0}, // 0432,
+    {IV('г'), 'r', 0}, // 0433
+    {IV('д'), 'a', 0}, // 0434,
+    {IV('е'), 'e', 0}, // 0435
+    {IV('ж'), '*', 0}, // 0436
+    {IV('з'), 'e', 0}, // 0437,
+    {IV('и'), 'u', 0}, // 0438
+    {IV('й'), 'u', 0}, // 0439,
+    {IV('к'), 'k', 0}, // 043A
+    {IV('л'), 'n', 0},
+    {IV('м'), 'm', 0},
+    {IV('н'), 'H', 0},
+    {IV('о'), 'o', 0},
+    {IV('п'), 'n', 0},
+    {IV('р'), 'p', 0},
+    {IV('с'), 'c', 0},
+    {IV('т'), 't', 0},
+    {IV('у'), 'y', 0},
+    {IV('ф'), 'q', 'p'},
+    {IV('х'), 'x', 0},
+    {IV('ц'), 'u', 0},
+    {IV('ч'), 'y', 0},
+    {IV('ш'), 'w', 0},
+    {IV('щ'), 'w', 0},
+    {IV('ъ'), 'b', 0},
+    {IV('ы'), 'b', '|'},
+    {IV('ь'), 'b', 0},
+    {IV('э'), 'e', 0},
+    {IV('ю'), '|', 'o'},
+    {IV('я'), 'g', 0}, // 044F
+    {IV('ё'), 'e', 0}, // 0451
+  #endif
+
+  {IV('•'), '.', 0}, // 2022 ·
+  {IV('℞'), 'P', 'x'}, // 211E ℞ Pt ASCII 158
+  {IV('™'), 'T', 'M'}, // 2122
+  {IV('←'), '<', '-'}, // 2190
+  {IV('→'), '-', '>'}, // 2192, Marlin special: '⮈⮉⮊⮋➤→⏵➟➠➡' LCD_STR_ARROW_RIGHT (0x03)
+  //{IV('↰'), '<', 0}, // 21B0, Marlin special: '⮥⮭⮉⇧↑↰⤴'  LCD_STR_UPLEVEL (0x04)
+  {IV('↰'), 0x03, 0}, // 21B0, Marlin special: '⮥⮭⮉⇧↑↰⤴'  LCD_STR_UPLEVEL (0x04)
+  {IV('↻'), 0x04, 0}, // 21BB Marlin special: '↻↺⟳⟲'  LCD_STR_REFRESH (0x01)
+  {IV('∼'), '~', 0}, // 223C
+  {IV('≈'), '~', '='}, // 2248
+  {IV('≠'), '!', '='}, // 2260
+  {IV('≡'), '=', 0}, // 2261
+  {IV('≤'), '<', '='},// 2264, ≤≥ ⩽⩾
+  {IV('≥'), '>', '='}, // 2265
+  {IV('⏱'), 0x07, 0}, // 23F1, Marlin special: '🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜🕝🕞🕟🕠🕡🕢🕣🕤🕥🕦🕧 ⌚⌛⏰⏱⏳⧖⧗'  LCD_STR_CLOCK (0x05)
+
+  {IV('゠'), '=', 0}, // 30A0
+
+  // ⏰⏱⏲⏳◴◵◶◷
+  // ⏻⏼♁♂
+  //{IV(''), 0x00, 0}, // Marlin special: ''  LCD_STR_BEDTEMP (0x07)
+  {IV('🌡'), 0x02, 0}, // D83CDF21 Marlin special: '🌡'  LCD_STR_THERMOMETER (0x08)
+  {IV('📂'), 0x05, 0}, // D83DDCC2 Marlin special: '📁📂'  LCD_STR_FOLDER (0x02)
+  //{IV(''), 0x06, 0}, // Marlin special: ''  LCD_STR_FEEDRATE (0x06)
+};

Некоторые файлы не были показаны из-за большого количества измененных файлов