diff --git a/src/lcd/HD44780/lcdprint_hd44780.cpp b/src/lcd/HD44780/lcdprint_hd44780.cpp
new file mode 100644
index 0000000..fe31c21
--- /dev/null
+++ b/src/lcd/HD44780/lcdprint_hd44780.cpp
@@ -0,0 +1,1144 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/**
+ * @file lcdprint_hd44780.cpp
+ * @brief LCD print api for HD44780
+ * @author Yunhui Fu (yhfudev@gmail.com)
+ * @version 1.0
+ * @date 2016-08-19
+ * @copyright GPL/BSD
+ */
+
+/**
+ * Due to the limitation of the HD44780 hardware, the current available LCD modules can only support
+ * Western(English), Cyrillic(Russian), Kana(Japanese) charsets.
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_MARLINUI_HD44780
+
+#include "../marlinui.h"
+#include "../../MarlinCore.h"
+
+#include "marlinui_HD44780.h"
+
+#include
+
+extern LCD_CLASS lcd;
+
+int lcd_glyph_height() { return 1; }
+
+typedef struct _hd44780_charmap_t {
+ lchar_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
+} hd44780_charmap_t;
+
+#ifdef __AVR__
+ #define IV(a) U##a
+#else
+ #define IV(a) L##a
+#endif
+
+static const hd44780_charmap_t g_hd44780_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
+static const hd44780_charmap_t g_hd44780_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)
+};
+
+/* return v1 - v2 */
+static int hd44780_charmap_compare(hd44780_charmap_t * v1, hd44780_charmap_t * v2) {
+ return (v1->uchar < v2->uchar) ? -1 : (v1->uchar > v2->uchar) ? 1 : 0;
+}
+
+static int pf_bsearch_cb_comp_hd4map_pgm(void *userdata, size_t idx, void * data_pin) {
+ hd44780_charmap_t localval;
+ hd44780_charmap_t *p_hd44780_charmap = (hd44780_charmap_t *)userdata;
+ memcpy_P(&localval, p_hd44780_charmap + idx, sizeof(localval));
+ return hd44780_charmap_compare(&localval, (hd44780_charmap_t *)data_pin);
+}
+
+void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) { lcd.setCursor(col, row); }
+
+void lcd_put_int(const int i) { lcd.print(i); }
+
+// return < 0 on error
+// return the advanced cols
+int lcd_put_lchar_max(const lchar_t &c, const pixel_len_t max_length) {
+
+ // find the HD44780 internal ROM first
+ int ret;
+ size_t idx = 0;
+ hd44780_charmap_t pinval;
+ hd44780_charmap_t *copy_address = nullptr;
+ pinval.uchar = c;
+ pinval.idx = -1;
+
+ if (max_length < 1) return 0;
+
+ // TODO: fix the '\\' that doesn't exist in the HD44870
+ if (c < 128) {
+ lcd.write((uint8_t)c);
+ return 1;
+ }
+ copy_address = nullptr;
+ ret = pf_bsearch_r((void *)g_hd44780_charmap_device, COUNT(g_hd44780_charmap_device), pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx);
+ if (ret >= 0) {
+ copy_address = (hd44780_charmap_t *)(g_hd44780_charmap_device + idx);
+ }
+ else {
+ ret = pf_bsearch_r((void *)g_hd44780_charmap_common, COUNT(g_hd44780_charmap_common), pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx);
+ if (ret >= 0) copy_address = (hd44780_charmap_t *)(g_hd44780_charmap_common + idx);
+ }
+
+ if (ret >= 0) {
+ hd44780_charmap_t localval;
+ // found
+ memcpy_P(&localval, copy_address, sizeof(localval));
+ lcd.write(localval.idx);
+ if (max_length >= 2 && localval.idx2 > 0) {
+ lcd.write(localval.idx2);
+ return 2;
+ }
+ return 1;
+ }
+
+ // Not found, print '?' instead
+ lcd.write((uint8_t)'?');
+ return 1;
+}
+
+/**
+ * @brief Draw a UTF-8 string
+ *
+ * @param utf8_str : the UTF-8 string
+ * @param cb_read_byte : the callback function to read one byte from the utf8_str (from RAM or ROM)
+ * @param max_length : the pixel length of the string allowed (or number of slots in HD44780)
+ *
+ * @return the number of pixels advanced
+ *
+ * Draw a UTF-8 string
+ */
+static int lcd_put_u8str_max_cb(const char * utf8_str, read_byte_cb_t cb_read_byte, const pixel_len_t max_length) {
+ pixel_len_t ret = 0;
+ const uint8_t *p = (uint8_t *)utf8_str;
+ while (ret < max_length) {
+ lchar_t wc;
+ p = get_utf8_value_cb(p, cb_read_byte, wc);
+ if (!wc) break;
+ ret += lcd_put_lchar_max(wc, max_length - ret);
+ }
+ return (int)ret;
+}
+
+int lcd_put_u8str_max(const char * utf8_str, const pixel_len_t max_length) {
+ return lcd_put_u8str_max_cb(utf8_str, read_byte_ram, max_length);
+}
+
+int lcd_put_u8str_max_P(PGM_P utf8_pstr, const pixel_len_t max_length) {
+ return lcd_put_u8str_max_cb(utf8_pstr, read_byte_rom, max_length);
+}
+
+#if ENABLED(DEBUG_LCDPRINT)
+
+ int test_hd44780_charmap(hd44780_charmap_t *data, size_t size, char *name, char flg_show_contents) {
+ int ret;
+ size_t idx = 0;
+ hd44780_charmap_t preval = {0, 0, 0};
+ hd44780_charmap_t pinval = {0, 0, 0};
+ char flg_error = 0;
+
+ int i;
+
+ TRACE("Test %s\n", name);
+
+ for (i = 0; i < size; i ++) {
+ memcpy_P(&pinval, &(data[i]), sizeof(pinval));
+
+ if (flg_show_contents) {
+ #if 1
+ TRACE("[% 4d] % 6" PRIu32 "(0x%04" PRIX32 ") --> 0x%02X,0x%02X%s\n", i, pinval.uchar, pinval.uchar, (unsigned int)(pinval.idx), (unsigned int)(pinval.idx2), (preval.uchar < pinval.uchar?"":" <--- ERROR"));
+ #else
+ TRACE("[% 4d]", i);
+ TRACE("% 6" PRIu32 "(0x%04" PRIX32 "),", pinval.uchar, pinval.uchar);
+ TRACE("0x%02X,", (unsigned int)(pinval.idx));
+ TRACE("0x%02X,", (unsigned int)(pinval.idx2));
+ TRACE("%s", (preval.uchar < pinval.uchar?"":" <--- ERROR"));
+ #endif
+ }
+ if (preval.uchar >= pinval.uchar) {
+ flg_error = 1;
+ //TRACE("Error: out of order in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
+ //return -1;
+ }
+ memcpy(&preval, &pinval, sizeof(pinval));
+
+ ret = pf_bsearch_r((void *)data, size, pf_bsearch_cb_comp_hd4map_pgm, (void *)&pinval, &idx);
+ if (ret < 0) {
+ flg_error = 1;
+ TRACE("Error: not found item in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
+ //return -1;
+ }
+ if (idx != i) {
+ flg_error = 1;
+ TRACE("Error: wrong index found item in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
+ //return -1;
+ }
+ }
+ if (flg_error) {
+ TRACE("\nError: in array %s\n\n", name);
+ return -1;
+ }
+ TRACE("\nPASS array %s\n\n", name);
+ return 0;
+ }
+
+ int test_hd44780_charmap_all() {
+ int flg_error = 0;
+ if (test_hd44780_charmap(g_hd44780_charmap_device, COUNT(g_hd44780_charmap_device), "g_hd44780_charmap_device", 0) < 0) {
+ flg_error = 1;
+ test_hd44780_charmap(g_hd44780_charmap_device, COUNT(g_hd44780_charmap_device), "g_hd44780_charmap_device", 1);
+ }
+ if (test_hd44780_charmap(g_hd44780_charmap_common, COUNT(g_hd44780_charmap_common), "g_hd44780_charmap_common", 0) < 0) {
+ flg_error = 1;
+ test_hd44780_charmap(g_hd44780_charmap_common, COUNT(g_hd44780_charmap_common), "g_hd44780_charmap_common", 1);
+ }
+ if (flg_error) {
+ TRACE("\nFAILED in hd44780 tests!\n");
+ return -1;
+ }
+ TRACE("\nPASS in hd44780 tests.\n");
+ return 0;
+ }
+
+#endif // DEBUG_LCDPRINT
+
+#endif // HAS_MARLINUI_HD44780
diff --git a/src/lcd/HD44780/marlinui_HD44780.cpp b/src/lcd/HD44780/marlinui_HD44780.cpp
new file mode 100644
index 0000000..b8dc8db
--- /dev/null
+++ b/src/lcd/HD44780/marlinui_HD44780.cpp
@@ -0,0 +1,1595 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+#include "../../inc/MarlinConfigPre.h"
+
+#if HAS_MARLINUI_HD44780
+
+/**
+ * marlinui_HD44780.cpp
+ *
+ * LCD display implementations for Hitachi HD44780.
+ * These are the most common LCD character displays.
+ */
+
+#include "marlinui_HD44780.h"
+#include "../marlinui.h"
+#include "../../libs/numtostr.h"
+
+#include "../../sd/cardreader.h"
+#include "../../module/temperature.h"
+#include "../../module/printcounter.h"
+#include "../../module/planner.h"
+#include "../../module/motion.h"
+
+#if DISABLED(LCD_PROGRESS_BAR) && BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT)
+ #include "../../feature/filwidth.h"
+ #include "../../gcode/parser.h"
+#endif
+
+#if EITHER(HAS_COOLER, LASER_COOLANT_FLOW_METER)
+ #include "../../feature/cooler.h"
+#endif
+
+#if ENABLED(I2C_AMMETER)
+ #include "../../feature/ammeter.h"
+#endif
+
+#if ENABLED(AUTO_BED_LEVELING_UBL)
+ #include "../../feature/bedlevel/bedlevel.h"
+#endif
+
+//
+// Create LCD instance and chipset-specific information
+//
+
+#if ENABLED(LCD_I2C_TYPE_PCF8575)
+
+ LCD_CLASS lcd(LCD_I2C_ADDRESS, LCD_I2C_PIN_EN, LCD_I2C_PIN_RW, LCD_I2C_PIN_RS, LCD_I2C_PIN_D4, LCD_I2C_PIN_D5, LCD_I2C_PIN_D6, LCD_I2C_PIN_D7);
+
+#elif EITHER(LCD_I2C_TYPE_MCP23017, LCD_I2C_TYPE_MCP23008)
+
+ LCD_CLASS lcd(LCD_I2C_ADDRESS OPTARG(DETECT_I2C_LCD_DEVICE, 1));
+
+#elif ENABLED(LCD_I2C_TYPE_PCA8574)
+
+ LCD_CLASS lcd(LCD_I2C_ADDRESS, LCD_WIDTH, LCD_HEIGHT);
+
+#elif ENABLED(SR_LCD_2W_NL)
+
+ // 2 wire Non-latching LCD SR from:
+ // https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection
+
+ LCD_CLASS lcd(SR_DATA_PIN, SR_CLK_PIN
+ #if PIN_EXISTS(SR_STROBE)
+ , SR_STROBE_PIN
+ #endif
+ );
+
+#elif ENABLED(SR_LCD_3W_NL)
+
+ // NewLiquidCrystal was not working
+ // https://github.com/mikeshub/SailfishLCD
+ // uses the code directly from Sailfish
+
+ LCD_CLASS lcd(SR_STROBE_PIN, SR_DATA_PIN, SR_CLK_PIN);
+
+#elif ENABLED(LCM1602)
+
+ LCD_CLASS lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
+
+#elif ENABLED(YHCB2004)
+
+ LCD_CLASS lcd(YHCB2004_CLK, 20, 4, YHCB2004_MOSI, YHCB2004_MISO); // CLK, cols, rows, MOSI, MISO
+
+#else
+
+ // Standard direct-connected LCD implementations
+ LCD_CLASS lcd(LCD_PINS_RS, LCD_PINS_ENABLE, LCD_PINS_D4, LCD_PINS_D5, LCD_PINS_D6, LCD_PINS_D7);
+
+#endif
+
+static void createChar_P(const char c, const byte * const ptr) {
+ byte temp[8];
+ LOOP_L_N(i, 8)
+ temp[i] = pgm_read_byte(&ptr[i]);
+ lcd.createChar(c, temp);
+}
+
+#if ENABLED(LCD_PROGRESS_BAR)
+ #define LCD_STR_PROGRESS "\x03\x04\x05"
+#endif
+
+#if ENABLED(LCD_USE_I2C_BUZZER)
+
+ void MarlinUI::buzz(const long duration, const uint16_t freq) {
+ if (sound_on) lcd.buzz(duration, freq);
+ }
+
+#endif
+
+void MarlinUI::set_custom_characters(const HD44780CharSet screen_charset/*=CHARSET_INFO*/) {
+ #if NONE(LCD_PROGRESS_BAR, SHOW_BOOTSCREEN)
+ UNUSED(screen_charset);
+ #endif
+
+ // CHARSET_BOOT
+ #if ENABLED(SHOW_BOOTSCREEN)
+ const static PROGMEM byte corner[4][8] = { {
+ B00000,
+ B00000,
+ B00000,
+ B00000,
+ B00001,
+ B00010,
+ B00100,
+ B00100
+ }, {
+ B00000,
+ B00000,
+ B00000,
+ B11100,
+ B11100,
+ B01100,
+ B00100,
+ B00100
+ }, {
+ B00100,
+ B00010,
+ B00001,
+ B00000,
+ B00000,
+ B00000,
+ B00000,
+ B00000
+ }, {
+ B00100,
+ B01000,
+ B10000,
+ B00000,
+ B00000,
+ B00000,
+ B00000,
+ B00000
+ } };
+ #endif // SHOW_BOOTSCREEN
+
+ // CHARSET_INFO
+ const static PROGMEM byte bedTemp[8] = {
+ B00000,
+ B11111,
+ B10101,
+ B10001,
+ B10101,
+ B11111,
+ B00000,
+ B00000
+ };
+
+ const static PROGMEM byte degree[8] = {
+ B01100,
+ B10010,
+ B10010,
+ B01100,
+ B00000,
+ B00000,
+ B00000,
+ B00000
+ };
+
+ const static PROGMEM byte thermometer[8] = {
+ B00100,
+ B01010,
+ B01010,
+ B01010,
+ B01010,
+ B10001,
+ B10001,
+ B01110
+ };
+
+ const static PROGMEM byte uplevel[8] = {
+ B00100,
+ B01110,
+ B11111,
+ B00100,
+ B11100,
+ B00000,
+ B00000,
+ B00000
+ };
+
+ const static PROGMEM byte feedrate[8] = {
+ #if LCD_INFO_SCREEN_STYLE == 1
+ B00000,
+ B00100,
+ B10010,
+ B01001,
+ B10010,
+ B00100,
+ B00000,
+ B00000
+ #else
+ B11100,
+ B10000,
+ B11000,
+ B10111,
+ B00101,
+ B00110,
+ B00101,
+ B00000
+ #endif
+ };
+
+ const static PROGMEM byte clock[8] = {
+ B00000,
+ B01110,
+ B10011,
+ B10101,
+ B10001,
+ B01110,
+ B00000,
+ B00000
+ };
+
+ #if ENABLED(LCD_PROGRESS_BAR)
+
+ // CHARSET_INFO
+ const static PROGMEM byte progress[3][8] = { {
+ B00000,
+ B10000,
+ B10000,
+ B10000,
+ B10000,
+ B10000,
+ B10000,
+ B00000
+ }, {
+ B00000,
+ B10100,
+ B10100,
+ B10100,
+ B10100,
+ B10100,
+ B10100,
+ B00000
+ }, {
+ B00000,
+ B10101,
+ B10101,
+ B10101,
+ B10101,
+ B10101,
+ B10101,
+ B00000
+ } };
+
+ #endif // LCD_PROGRESS_BAR
+
+ #if BOTH(SDSUPPORT, HAS_MARLINUI_MENU)
+
+ // CHARSET_MENU
+ const static PROGMEM byte refresh[8] = {
+ B00000,
+ B00110,
+ B11001,
+ B11000,
+ B00011,
+ B10011,
+ B01100,
+ B00000,
+ };
+ const static PROGMEM byte folder[8] = {
+ B00000,
+ B11100,
+ B11111,
+ B10001,
+ B10001,
+ B11111,
+ B00000,
+ B00000
+ };
+
+ #endif // SDSUPPORT
+
+ #if ENABLED(SHOW_BOOTSCREEN)
+ // Set boot screen corner characters
+ if (screen_charset == CHARSET_BOOT) {
+ for (uint8_t i = 4; i--;)
+ createChar_P(i, corner[i]);
+ }
+ else
+ #endif
+ { // Info Screen uses 5 special characters
+ createChar_P(LCD_STR_BEDTEMP[0], bedTemp);
+ createChar_P(LCD_STR_DEGREE[0], degree);
+ createChar_P(LCD_STR_THERMOMETER[0], thermometer);
+ createChar_P(LCD_STR_FEEDRATE[0], feedrate);
+ createChar_P(LCD_STR_CLOCK[0], clock);
+
+ #if ENABLED(LCD_PROGRESS_BAR)
+ if (screen_charset == CHARSET_INFO) { // 3 Progress bar characters for info screen
+ for (int16_t i = 3; i--;)
+ createChar_P(LCD_STR_PROGRESS[i], progress[i]);
+ }
+ else
+ #endif
+ {
+ createChar_P(LCD_STR_UPLEVEL[0], uplevel);
+ #if BOTH(SDSUPPORT, HAS_MARLINUI_MENU)
+ // SD Card sub-menu special characters
+ createChar_P(LCD_STR_REFRESH[0], refresh);
+ createChar_P(LCD_STR_FOLDER[0], folder);
+ #endif
+ }
+ }
+
+}
+
+void MarlinUI::init_lcd() {
+
+ #if ENABLED(LCD_I2C_TYPE_PCF8575)
+ lcd.begin(LCD_WIDTH, LCD_HEIGHT);
+ #ifdef LCD_I2C_PIN_BL
+ lcd.setBacklightPin(LCD_I2C_PIN_BL, POSITIVE);
+ lcd.setBacklight(HIGH);
+ #endif
+
+ #elif ENABLED(LCD_I2C_TYPE_MCP23017)
+ lcd.setMCPType(LTI_TYPE_MCP23017);
+ lcd.begin(LCD_WIDTH, LCD_HEIGHT);
+ update_indicators();
+
+ #elif ENABLED(LCD_I2C_TYPE_MCP23008)
+ lcd.setMCPType(LTI_TYPE_MCP23008);
+ lcd.begin(LCD_WIDTH, LCD_HEIGHT);
+
+ #elif ENABLED(LCD_I2C_TYPE_PCA8574)
+ lcd.init();
+ lcd.backlight();
+
+ #else
+ lcd.begin(LCD_WIDTH, LCD_HEIGHT);
+ #endif
+
+ set_custom_characters(on_status_screen() ? CHARSET_INFO : CHARSET_MENU);
+
+ lcd.clear();
+}
+
+bool MarlinUI::detected() {
+ return TERN1(DETECT_I2C_LCD_DEVICE, lcd.LcdDetected() == 1);
+}
+
+#if HAS_SLOW_BUTTONS
+ uint8_t MarlinUI::read_slow_buttons() {
+ #if ENABLED(LCD_I2C_TYPE_MCP23017)
+ // Reading these buttons is too slow for interrupt context
+ // so they are read during LCD update in the main loop.
+ uint8_t slow_bits = lcd.readButtons()
+ #if !BUTTON_EXISTS(ENC)
+ << B_I2C_BTN_OFFSET
+ #endif
+ ;
+ #if ENABLED(LCD_I2C_VIKI)
+ if ((slow_bits & (B_MI | B_RI)) && PENDING(millis(), next_button_update_ms)) // LCD clicked
+ slow_bits &= ~(B_MI | B_RI); // Disable LCD clicked buttons if screen is updated
+ #endif
+ return slow_bits;
+ #endif // LCD_I2C_TYPE_MCP23017
+ }
+#endif
+
+void MarlinUI::clear_lcd() { lcd.clear(); }
+
+#if ENABLED(SHOW_BOOTSCREEN)
+
+ void lcd_erase_line(const lcd_uint_t line) {
+ lcd_moveto(0, line);
+ for (uint8_t i = LCD_WIDTH + 1; --i;)
+ lcd_put_lchar(' ');
+ }
+
+ // Scroll the PSTR 'text' in a 'len' wide field for 'time' milliseconds at position col,line
+ void lcd_scroll(const lcd_uint_t col, const lcd_uint_t line, FSTR_P const ftxt, const uint8_t len, const int16_t time) {
+ uint8_t slen = utf8_strlen(ftxt);
+ if (slen < len) {
+ lcd_put_u8str_max(col, line, ftxt, len);
+ for (; slen < len; ++slen) lcd_put_lchar(' ');
+ safe_delay(time);
+ }
+ else {
+ PGM_P p = FTOP(ftxt);
+ int dly = time / _MAX(slen, 1);
+ LOOP_LE_N(i, slen) {
+
+ // Print the text at the correct place
+ lcd_put_u8str_max_P(col, line, p, len);
+
+ // Fill with spaces
+ for (uint8_t ix = slen - i; ix < len; ++ix) lcd_put_lchar(' ');
+
+ // Delay
+ safe_delay(dly);
+
+ // Advance to the next UTF8 valid position
+ p++;
+ while (!START_OF_UTF8_CHAR(pgm_read_byte(p))) p++;
+ }
+ }
+ }
+
+ static void logo_lines(FSTR_P const extra) {
+ int16_t indent = (LCD_WIDTH - 8 - utf8_strlen(extra)) / 2;
+ lcd_put_lchar(indent, 0, '\x00'); lcd_put_u8str(F( "------" )); lcd_put_lchar('\x01');
+ lcd_put_u8str(indent, 1, F("|Marlin|")); lcd_put_u8str(extra);
+ lcd_put_lchar(indent, 2, '\x02'); lcd_put_u8str(F( "------" )); lcd_put_lchar('\x03');
+ }
+
+ void MarlinUI::show_bootscreen() {
+ set_custom_characters(CHARSET_BOOT);
+ lcd.clear();
+
+ #define LCD_EXTRA_SPACE (LCD_WIDTH-8)
+
+ #define CENTER_OR_SCROLL(STRING,DELAY) { \
+ lcd_erase_line(3); \
+ const int len = utf8_strlen(STRING); \
+ if (len <= LCD_WIDTH) { \
+ lcd_put_u8str((LCD_WIDTH - len) / 2, 3, F(STRING)); \
+ safe_delay(DELAY); \
+ } \
+ else \
+ lcd_scroll(0, 3, F(STRING), LCD_WIDTH, DELAY); \
+ }
+
+ //
+ // Show the Marlin logo with splash line 1
+ //
+ if (LCD_EXTRA_SPACE >= utf8_strlen(SHORT_BUILD_VERSION) + 1) {
+ //
+ // Show the Marlin logo, splash line1, and splash line 2
+ //
+ logo_lines(F(" " SHORT_BUILD_VERSION));
+ CENTER_OR_SCROLL(MARLIN_WEBSITE_URL, 2000);
+ }
+ else {
+ //
+ // Show the Marlin logo and short build version
+ // After a delay show the website URL
+ //
+ logo_lines(FPSTR(NUL_STR));
+ CENTER_OR_SCROLL(SHORT_BUILD_VERSION, 1500);
+ CENTER_OR_SCROLL(MARLIN_WEBSITE_URL, 1500);
+ #ifdef STRING_SPLASH_LINE3
+ CENTER_OR_SCROLL(STRING_SPLASH_LINE3, 1500);
+ #endif
+ }
+ }
+
+ void MarlinUI::bootscreen_completion(const millis_t) {
+ lcd.clear();
+ safe_delay(100);
+ set_custom_characters(CHARSET_INFO);
+ lcd.clear();
+ }
+
+#endif // SHOW_BOOTSCREEN
+
+void MarlinUI::draw_kill_screen() {
+ lcd_uint_t x = 0, y = 0;
+ lcd_put_u8str(x, y, status_message);
+ y = 2;
+ #if LCD_HEIGHT >= 4
+ lcd_put_u8str(x, y++, GET_TEXT_F(MSG_HALTED));
+ #endif
+ lcd_put_u8str(x, y, GET_TEXT_F(MSG_PLEASE_RESET));
+}
+
+//
+// Before homing, blink '123' <-> '???'.
+// Homed but unknown... '123' <-> ' '.
+// Homed and known, display constantly.
+//
+FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const bool blink) {
+ lcd_put_lchar('X' + uint8_t(axis));
+ if (blink)
+ lcd_put_u8str(value);
+ else if (axis_should_home(axis))
+ while (const char c = *value++) lcd_put_lchar(c <= '.' ? c : '?');
+ else if (NONE(HOME_AFTER_DEACTIVATE, DISABLE_REDUCED_ACCURACY_WARNING) && !axis_is_trusted(axis))
+ lcd_put_u8str(axis == Z_AXIS ? F(" ") : F(" "));
+ else
+ lcd_put_u8str(value);
+}
+
+
+FORCE_INLINE void _draw_heater_status(const heater_id_t heater_id, const char prefix, const bool blink) {
+ #if HAS_HEATED_BED
+ const bool isBed = TERN(HAS_HEATED_CHAMBER, heater_id == H_BED, heater_id < 0);
+ const celsius_t t1 = (isBed ? thermalManager.wholeDegBed() : thermalManager.wholeDegHotend(heater_id)),
+ t2 = (isBed ? thermalManager.degTargetBed() : thermalManager.degTargetHotend(heater_id));
+ #else
+ const celsius_t t1 = thermalManager.wholeDegHotend(heater_id), t2 = thermalManager.degTargetHotend(heater_id);
+ #endif
+
+ if (prefix >= 0) lcd_put_lchar(prefix);
+
+ lcd_put_u8str(t1 < 0 ? "err" : i16tostr3rj(t1));
+ lcd_put_lchar('/');
+
+ #if !HEATER_IDLE_HANDLER
+ UNUSED(blink);
+ #else
+ if (!blink && thermalManager.heater_idle[thermalManager.idle_index_for_id(heater_id)].timed_out) {
+ lcd_put_lchar(' ');
+ if (t2 >= 10) lcd_put_lchar(' ');
+ if (t2 >= 100) lcd_put_lchar(' ');
+ }
+ else
+ #endif
+ lcd_put_u8str(i16tostr3left(t2));
+
+ if (prefix >= 0) {
+ lcd_put_lchar(LCD_STR_DEGREE[0]);
+ lcd_put_lchar(' ');
+ if (t2 < 10) lcd_put_lchar(' ');
+ }
+}
+
+#if HAS_COOLER
+FORCE_INLINE void _draw_cooler_status(const char prefix, const bool blink) {
+ const celsius_t t2 = thermalManager.degTargetCooler();
+
+ if (prefix >= 0) lcd_put_lchar(prefix);
+
+ lcd_put_u8str(i16tostr3rj(thermalManager.wholeDegCooler()));
+ lcd_put_lchar('/');
+
+ #if !HEATER_IDLE_HANDLER
+ UNUSED(blink);
+ #else
+ if (!blink && thermalManager.heater_idle[thermalManager.idle_index_for_id(heater_id)].timed_out) {
+ lcd_put_lchar(' ');
+ if (t2 >= 10) lcd_put_lchar(' ');
+ if (t2 >= 100) lcd_put_lchar(' ');
+ }
+ else
+ #endif
+ lcd_put_u8str(i16tostr3left(t2));
+
+ if (prefix >= 0) {
+ lcd_put_lchar(LCD_STR_DEGREE[0]);
+ lcd_put_lchar(' ');
+ if (t2 < 10) lcd_put_lchar(' ');
+ }
+}
+#endif
+
+#if ENABLED(LASER_COOLANT_FLOW_METER)
+ FORCE_INLINE void _draw_flowmeter_status() {
+ lcd_put_u8str("~");
+ lcd_put_u8str(ftostr11ns(cooler.flowrate));
+ lcd_put_lchar('L');
+ }
+#endif
+
+#if ENABLED(I2C_AMMETER)
+ FORCE_INLINE void _draw_ammeter_status() {
+ lcd_put_u8str(" ");
+ ammeter.read();
+ if (ammeter.current <= 0.999f) {
+ lcd_put_u8str(ui16tostr3rj(uint16_t(ammeter.current * 1000 + 0.5f)));
+ lcd_put_u8str("mA");
+ }
+ else {
+ lcd_put_u8str(ftostr12ns(ammeter.current));
+ lcd_put_lchar('A');
+ }
+ }
+#endif
+
+FORCE_INLINE void _draw_bed_status(const bool blink) {
+ _draw_heater_status(H_BED, TERN0(HAS_LEVELING, blink && planner.leveling_active) ? '_' : LCD_STR_BEDTEMP[0], blink);
+}
+
+#if HAS_PRINT_PROGRESS
+
+ FORCE_INLINE void _draw_print_progress() {
+ const uint8_t progress = ui.get_progress_percent();
+ lcd_put_u8str(F(TERN(SDSUPPORT, "SD", "P:")));
+ if (progress)
+ lcd_put_u8str(ui8tostr3rj(progress));
+ else
+ lcd_put_u8str(F("---"));
+ lcd_put_lchar('%');
+ }
+
+#endif
+
+#if ENABLED(LCD_PROGRESS_BAR)
+
+ void MarlinUI::draw_progress_bar(const uint8_t percent) {
+ const int16_t tix = int16_t(percent * (LCD_WIDTH) * 3) / 100,
+ cel = tix / 3,
+ rem = tix % 3;
+ uint8_t i = LCD_WIDTH;
+ char msg[LCD_WIDTH + 1], b = ' ';
+ msg[LCD_WIDTH] = '\0';
+ while (i--) {
+ if (i == cel - 1)
+ b = LCD_STR_PROGRESS[2];
+ else if (i == cel && rem != 0)
+ b = LCD_STR_PROGRESS[rem - 1];
+ msg[i] = b;
+ }
+ lcd_put_u8str(msg);
+ }
+
+#endif // LCD_PROGRESS_BAR
+
+void MarlinUI::draw_status_message(const bool blink) {
+
+ lcd_moveto(0, LCD_HEIGHT - 1);
+
+ #if ENABLED(LCD_PROGRESS_BAR)
+
+ // Draw the progress bar if the message has shown long enough
+ // or if there is no message set.
+ if (ELAPSED(millis(), progress_bar_ms + PROGRESS_BAR_MSG_TIME) || !has_status()) {
+ const uint8_t progress = get_progress_percent();
+ if (progress > 2) return draw_progress_bar(progress);
+ }
+
+ #elif BOTH(FILAMENT_LCD_DISPLAY, SDSUPPORT)
+
+ // Alternate Status message and Filament display
+ if (ELAPSED(millis(), next_filament_display)) {
+ lcd_put_u8str(F("Dia "));
+ lcd_put_u8str(ftostr12ns(filwidth.measured_mm));
+ lcd_put_u8str(F(" V"));
+ lcd_put_u8str(i16tostr3rj(planner.volumetric_percent(parser.volumetric_enabled)));
+ lcd_put_lchar('%');
+ return;
+ }
+
+ #endif // FILAMENT_LCD_DISPLAY && SDSUPPORT
+
+ #if ENABLED(STATUS_MESSAGE_SCROLLING)
+ static bool last_blink = false;
+
+ // Get the UTF8 character count of the string
+ uint8_t slen = utf8_strlen(status_message);
+
+ // If the string fits into the LCD, just print it and do not scroll it
+ if (slen <= LCD_WIDTH) {
+
+ // The string isn't scrolling and may not fill the screen
+ lcd_put_u8str(status_message);
+
+ // Fill the rest with spaces
+ while (slen < LCD_WIDTH) { lcd_put_lchar(' '); ++slen; }
+ }
+ else {
+ // String is larger than the available space in screen.
+
+ // Get a pointer to the next valid UTF8 character
+ // and the string remaining length
+ uint8_t rlen;
+ const char *stat = status_and_len(rlen);
+ lcd_put_u8str_max(stat, LCD_WIDTH); // The string leaves space
+
+ // If the remaining string doesn't completely fill the screen
+ if (rlen < LCD_WIDTH) {
+ uint8_t chars = LCD_WIDTH - rlen; // Amount of space left in characters
+ lcd_put_lchar(' '); // Always at 1+ spaces left, draw a space
+ if (--chars) { // Draw a second space if there's room
+ lcd_put_lchar(' ');
+ if (--chars) { // Draw a third space if there's room
+ lcd_put_lchar(' ');
+ if (--chars)
+ lcd_put_u8str_max(status_message, chars); // Print a second copy of the message
+ }
+ }
+ }
+ if (last_blink != blink) {
+ last_blink = blink;
+ advance_status_scroll();
+ }
+ }
+ #else
+ UNUSED(blink);
+
+ // Get the UTF8 character count of the string
+ uint8_t slen = utf8_strlen(status_message);
+
+ // Just print the string to the LCD
+ lcd_put_u8str_max(status_message, LCD_WIDTH);
+
+ // Fill the rest with spaces if there are missing spaces
+ while (slen < LCD_WIDTH) {
+ lcd_put_lchar(' ');
+ ++slen;
+ }
+ #endif
+}
+
+/**
+ * LCD_INFO_SCREEN_STYLE 0 : Classic Status Screen
+ *
+ * 16x2 |000/000 B000/000|
+ * |0123456789012345|
+ *
+ * 16x4 |000/000 B000/000|
+ * |SD---% Z 000.00|
+ * |F---% T--:--|
+ * |0123456789012345|
+ *
+ * 20x2 |T000/000° B000/000° |
+ * |01234567890123456789|
+ *
+ * 20x4 |T000/000° B000/000° |
+ * |X 000 Y 000 Z000.000|
+ * |F---% SD---% T--:--|
+ * |01234567890123456789|
+ *
+ * LCD_INFO_SCREEN_STYLE 1 : Průša-style Status Screen
+ *
+ * |T000/000° Z 000.00 |
+ * |B000/000° F---% |
+ * |SD---% T--:-- |
+ * |01234567890123456789|
+ *
+ * |T000/000° Z 000.00 |
+ * |T000/000° F---% |
+ * |B000/000° SD---% |
+ * |01234567890123456789|
+ */
+
+inline uint8_t draw_elapsed_or_remaining_time(uint8_t timepos, const bool blink) {
+ char buffer[14];
+
+ #if ENABLED(SHOW_REMAINING_TIME)
+ const bool show_remain = TERN1(ROTATE_PROGRESS_DISPLAY, blink) && printingIsActive();
+ if (show_remain) {
+ #if ENABLED(USE_M73_REMAINING_TIME)
+ duration_t remaining = ui.get_remaining_time();
+ #else
+ uint8_t progress = ui.get_progress_percent();
+ uint32_t elapsed = print_job_timer.duration();
+ duration_t remaining = (progress > 0) ? ((elapsed * 25600 / progress) >> 8) - elapsed : 0;
+ #endif
+ timepos -= remaining.toDigital(buffer);
+ lcd_put_lchar(timepos, 2, 'R');
+ }
+ #else
+ constexpr bool show_remain = false;
+ #endif
+
+ if (!show_remain) {
+ duration_t elapsed = print_job_timer.duration();
+ timepos -= elapsed.toDigital(buffer);
+ lcd_put_lchar(timepos, 2, LCD_STR_CLOCK[0]);
+ }
+ lcd_put_u8str(buffer);
+ return timepos;
+}
+
+void MarlinUI::draw_status_screen() {
+
+ const bool blink = get_blink();
+ lcd_moveto(0, 0);
+
+ #if LCD_INFO_SCREEN_STYLE == 0
+
+ // ========== Line 1 ==========
+
+ #if LCD_WIDTH < 20
+
+ //
+ // Hotend 0 Temperature
+ //
+ #if HAS_HOTEND
+ _draw_heater_status(H_E0, -1, blink);
+
+ //
+ // Hotend 1 or Bed Temperature
+ //
+ #if HAS_MULTI_HOTEND
+ lcd_moveto(8, 0);
+ _draw_heater_status(H_E1, LCD_STR_THERMOMETER[0], blink);
+ #elif HAS_HEATED_BED
+ lcd_moveto(8, 0);
+ _draw_bed_status(blink);
+ #endif
+ #endif
+
+ #else // LCD_WIDTH >= 20
+
+ //
+ // Hotend 0 Temperature
+ //
+ #if HAS_HOTEND
+ _draw_heater_status(H_E0, LCD_STR_THERMOMETER[0], blink);
+
+ //
+ // Hotend 1 or Bed Temperature
+ //
+ #if HAS_MULTI_HOTEND
+ lcd_moveto(10, 0);
+ _draw_heater_status(H_E1, LCD_STR_THERMOMETER[0], blink);
+ #elif HAS_HEATED_BED
+ lcd_moveto(10, 0);
+ _draw_bed_status(blink);
+ #endif
+ #endif
+
+ TERN_(HAS_COOLER, _draw_cooler_status('*', blink));
+ TERN_(LASER_COOLANT_FLOW_METER, _draw_flowmeter_status());
+ TERN_(I2C_AMMETER, _draw_ammeter_status());
+
+ #endif // LCD_WIDTH >= 20
+
+ // ========== Line 2 ==========
+
+ #if LCD_HEIGHT > 2
+
+ #if LCD_WIDTH < 20
+
+ #if HAS_PRINT_PROGRESS
+ lcd_moveto(0, 2);
+ _draw_print_progress();
+ #endif
+
+ #else // LCD_WIDTH >= 20
+
+ lcd_moveto(0, 1);
+
+ // If the first line has two extruder temps,
+ // show more temperatures on the next line
+
+ #if HOTENDS > 2 || (HAS_MULTI_HOTEND && HAS_HEATED_BED)
+
+ #if HOTENDS > 2
+ _draw_heater_status(H_E2, LCD_STR_THERMOMETER[0], blink);
+ lcd_moveto(10, 1);
+ #endif
+
+ _draw_bed_status(blink);
+
+ #else // HOTENDS <= 2 && (HOTENDS <= 1 || !HAS_HEATED_BED)
+
+ #if HAS_DUAL_MIXING
+
+ // Two-component mix / gradient instead of XY
+
+ char mixer_messages[12];
+ const char *mix_label;
+ #if ENABLED(GRADIENT_MIX)
+ if (mixer.gradient.enabled) {
+ mixer.update_mix_from_gradient();
+ mix_label = "Gr";
+ }
+ else
+ #endif
+ {
+ mixer.update_mix_from_vtool();
+ mix_label = "Mx";
+ }
+ sprintf_P(mixer_messages, PSTR("%s %d;%d%% "), mix_label, int(mixer.mix[0]), int(mixer.mix[1]));
+ lcd_put_u8str(mixer_messages);
+
+ #else // !HAS_DUAL_MIXING
+
+ const bool show_e_total = TERN0(LCD_SHOW_E_TOTAL, printingIsActive());
+
+ if (show_e_total) {
+ #if ENABLED(LCD_SHOW_E_TOTAL)
+ char tmp[20];
+ const uint8_t escale = e_move_accumulator >= 100000.0f ? 10 : 1; // After 100m switch to cm
+ sprintf_P(tmp, PSTR("E %ld%cm "), uint32_t(_MAX(e_move_accumulator, 0.0f)) / escale, escale == 10 ? 'c' : 'm'); // 1234567mm
+ lcd_put_u8str(tmp);
+ #endif
+ }
+ else {
+ const xy_pos_t lpos = current_position.asLogical();
+ _draw_axis_value(X_AXIS, ftostr4sign(lpos.x), blink);
+ lcd_put_lchar(' ');
+ _draw_axis_value(Y_AXIS, ftostr4sign(lpos.y), blink);
+ }
+
+ #endif // !HAS_DUAL_MIXING
+
+ #endif // HOTENDS <= 2 && (HOTENDS <= 1 || !HAS_HEATED_BED)
+
+ #endif // LCD_WIDTH >= 20
+
+ lcd_moveto(LCD_WIDTH - 8, 1);
+ _draw_axis_value(Z_AXIS, ftostr52sp(LOGICAL_Z_POSITION(current_position.z)), blink);
+
+ #if HAS_LEVELING && !HAS_HEATED_BED
+ lcd_put_lchar(planner.leveling_active || blink ? '_' : ' ');
+ #endif
+
+ #endif // LCD_HEIGHT > 2
+
+ // ========== Line 3 ==========
+
+ #if LCD_HEIGHT > 3
+
+ lcd_put_lchar(0, 2, LCD_STR_FEEDRATE[0]);
+ lcd_put_u8str(i16tostr3rj(feedrate_percentage));
+ lcd_put_lchar('%');
+
+ const uint8_t timepos = draw_elapsed_or_remaining_time(LCD_WIDTH - 1, blink);
+
+ #if LCD_WIDTH >= 20
+ lcd_moveto(timepos - 7, 2);
+ #if HAS_PRINT_PROGRESS
+ _draw_print_progress();
+ #else
+ char c;
+ uint16_t per;
+ #if HAS_FAN0
+ if (true
+ #if EXTRUDERS && ENABLED(ADAPTIVE_FAN_SLOWING)
+ && (blink || thermalManager.fan_speed_scaler[0] < 128)
+ #endif
+ ) {
+ uint16_t spd = thermalManager.fan_speed[0];
+ if (blink) c = 'F';
+ #if ENABLED(ADAPTIVE_FAN_SLOWING)
+ else { c = '*'; spd = thermalManager.scaledFanSpeed(0, spd); }
+ #endif
+ per = thermalManager.pwmToPercent(spd);
+ }
+ else
+ #endif
+ {
+ #if HAS_EXTRUDERS
+ c = 'E';
+ per = planner.flow_percentage[0];
+ #endif
+ }
+ lcd_put_lchar(c);
+ lcd_put_u8str(i16tostr3rj(per));
+ lcd_put_lchar('%');
+ #endif
+ #endif
+
+ #endif // LCD_HEIGHT > 3
+
+ #elif LCD_INFO_SCREEN_STYLE == 1
+
+ // ========== Line 1 ==========
+
+ //
+ // Hotend 0 Temperature
+ //
+ _draw_heater_status(H_E0, LCD_STR_THERMOMETER[0], blink);
+
+ //
+ // Z Coordinate
+ //
+ lcd_moveto(LCD_WIDTH - 9, 0);
+ _draw_axis_value(Z_AXIS, ftostr52sp(LOGICAL_Z_POSITION(current_position.z)), blink);
+
+ #if HAS_LEVELING && (HAS_MULTI_HOTEND || !HAS_HEATED_BED)
+ lcd_put_lchar(LCD_WIDTH - 1, 0, planner.leveling_active || blink ? '_' : ' ');
+ #endif
+
+ // ========== Line 2 ==========
+
+ //
+ // Hotend 1 or Bed Temperature
+ //
+ lcd_moveto(0, 1);
+ #if HAS_MULTI_HOTEND
+ _draw_heater_status(H_E1, LCD_STR_THERMOMETER[0], blink);
+ #elif HAS_HEATED_BED
+ _draw_bed_status(blink);
+ #endif
+
+ lcd_put_lchar(LCD_WIDTH - 9, 1, LCD_STR_FEEDRATE[0]);
+ lcd_put_u8str(i16tostr3rj(feedrate_percentage));
+ lcd_put_lchar('%');
+
+ // ========== Line 3 ==========
+
+ //
+ // SD Percent, Hotend 2, or Bed
+ //
+ lcd_moveto(0, 2);
+ #if HOTENDS > 2
+ _draw_heater_status(H_E2, LCD_STR_THERMOMETER[0], blink);
+ #elif HAS_MULTI_HOTEND && HAS_HEATED_BED
+ _draw_bed_status(blink);
+ #elif HAS_PRINT_PROGRESS
+ #define DREW_PRINT_PROGRESS 1
+ _draw_print_progress();
+ #endif
+
+ //
+ // Elapsed Time or SD Percent
+ //
+ lcd_moveto(LCD_WIDTH - 9, 2);
+
+ #if HAS_PRINT_PROGRESS && !DREW_PRINT_PROGRESS
+
+ _draw_print_progress();
+
+ #else
+
+ (void)draw_elapsed_or_remaining_time(LCD_WIDTH - 4, blink);
+
+ #endif
+
+ #endif // LCD_INFO_SCREEN_STYLE 1
+
+ // ========= Last Line ========
+
+ //
+ // Status Message (which may be a Progress Bar or Filament display)
+ //
+ draw_status_message(blink);
+}
+
+#if HAS_MARLINUI_MENU
+
+ #include "../menu/menu.h"
+
+ #if ENABLED(ADVANCED_PAUSE_FEATURE)
+
+ void MarlinUI::draw_hotend_status(const uint8_t row, const uint8_t extruder) {
+ if (row < LCD_HEIGHT) {
+ lcd_moveto(LCD_WIDTH - 9, row);
+ _draw_heater_status((heater_id_t)extruder, LCD_STR_THERMOMETER[0], get_blink());
+ }
+ }
+
+ #endif // ADVANCED_PAUSE_FEATURE
+
+ // Draw a static item with no left-right margin required. Centered by default.
+ void MenuItem_static::draw(const uint8_t row, FSTR_P const fstr, const uint8_t style/*=SS_DEFAULT*/, const char * const vstr/*=nullptr*/) {
+ int8_t n = LCD_WIDTH;
+ lcd_moveto(0, row);
+ const int8_t plen = fstr ? utf8_strlen(fstr) : 0,
+ vlen = vstr ? utf8_strlen(vstr) : 0;
+ if (style & SS_CENTER) {
+ int8_t pad = (LCD_WIDTH - plen - vlen) / 2;
+ while (--pad >= 0) { lcd_put_lchar(' '); n--; }
+ }
+ if (plen) n = lcd_put_u8str(fstr, itemIndex, itemStringC, itemStringF, n);
+ if (vlen) n -= lcd_put_u8str_max(vstr, n);
+ for (; n > 0; --n) lcd_put_lchar(' ');
+ }
+
+ // Draw a generic menu item with pre_char (if selected) and post_char
+ void MenuItemBase::_draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char pre_char, const char post_char) {
+ lcd_put_lchar(0, row, sel ? pre_char : ' ');
+ uint8_t n = lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, LCD_WIDTH - 2);
+ for (; n; --n) lcd_put_lchar(' ');
+ lcd_put_lchar(post_char);
+ }
+
+ // Draw a menu item with a (potentially) editable value
+ void MenuEditItemBase::draw(const bool sel, const uint8_t row, FSTR_P const ftpl, const char * const inStr, const bool pgm) {
+ const uint8_t vlen = inStr ? (pgm ? utf8_strlen_P(inStr) : utf8_strlen(inStr)) : 0;
+ lcd_put_lchar(0, row, sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
+ uint8_t n = lcd_put_u8str(ftpl, itemIndex, itemStringC, itemStringF, LCD_WIDTH - 2 - vlen);
+ if (vlen) {
+ lcd_put_lchar(':');
+ for (; n; --n) lcd_put_lchar(' ');
+ if (pgm) lcd_put_u8str_P(inStr); else lcd_put_u8str(inStr);
+ }
+ }
+
+ // Low-level draw_edit_screen can be used to draw an edit screen from anyplace
+ void MenuEditItemBase::draw_edit_screen(FSTR_P const ftpl, const char * const value/*=nullptr*/) {
+ ui.encoder_direction_normal();
+ uint8_t n = lcd_put_u8str(0, 1, ftpl, itemIndex, itemStringC, itemStringF, LCD_WIDTH - 1);
+ if (value) {
+ lcd_put_lchar(':'); n--;
+ const uint8_t len = utf8_strlen(value) + 1; // Plus one for a leading space
+ const lcd_uint_t valrow = n < len ? 2 : 1; // Value on the next row if it won't fit
+ lcd_put_lchar(LCD_WIDTH - len, valrow, ' '); // Right-justified, padded, leading space
+ lcd_put_u8str(value);
+ }
+ }
+
+ // The Select Screen presents a prompt and two "buttons"
+ void MenuItem_confirm::draw_select_screen(FSTR_P const yes, FSTR_P const no, const bool yesno, FSTR_P const pref, const char * const string/*=nullptr*/, FSTR_P const suff/*=nullptr*/) {
+ ui.draw_select_screen_prompt(pref, string, suff);
+ if (no) {
+ SETCURSOR(0, LCD_HEIGHT - 1);
+ lcd_put_lchar(yesno ? ' ' : '['); lcd_put_u8str(no); lcd_put_lchar(yesno ? ' ' : ']');
+ }
+ if (yes) {
+ SETCURSOR_RJ(utf8_strlen(yes) + 2, LCD_HEIGHT - 1);
+ lcd_put_lchar(yesno ? '[' : ' '); lcd_put_u8str(yes); lcd_put_lchar(yesno ? ']' : ' ');
+ }
+ }
+
+ #if ENABLED(SDSUPPORT)
+
+ void MenuItem_sdbase::draw(const bool sel, const uint8_t row, FSTR_P const, CardReader &theCard, const bool isDir) {
+ lcd_put_lchar(0, row, sel ? LCD_STR_ARROW_RIGHT[0] : ' ');
+ constexpr uint8_t maxlen = LCD_WIDTH - 2;
+ uint8_t n = maxlen - lcd_put_u8str_max(ui.scrolled_filename(theCard, maxlen, row, sel), maxlen);
+ for (; n; --n) lcd_put_lchar(' ');
+ lcd_put_lchar(isDir ? LCD_STR_FOLDER[0] : ' ');
+ }
+
+ #endif
+
+ #if ENABLED(LCD_HAS_STATUS_INDICATORS)
+
+ void MarlinUI::update_indicators() {
+ // Set the LEDS - referred to as backlights by the LiquidTWI2 library
+ static uint8_t ledsprev = 0;
+ uint8_t leds = 0;
+
+ if (TERN0(HAS_HEATED_BED, thermalManager.degTargetBed() > 0)) leds |= LED_A;
+ if (TERN0(HAS_HOTEND, thermalManager.degTargetHotend(0) > 0)) leds |= LED_B;
+
+ #if HAS_FAN
+ if ( TERN0(HAS_FAN0, thermalManager.fan_speed[0])
+ || TERN0(HAS_FAN1, thermalManager.fan_speed[1])
+ || TERN0(HAS_FAN2, thermalManager.fan_speed[2])
+ || TERN0(HAS_FAN3, thermalManager.fan_speed[3])
+ || TERN0(HAS_FAN4, thermalManager.fan_speed[4])
+ || TERN0(HAS_FAN5, thermalManager.fan_speed[5])
+ || TERN0(HAS_FAN6, thermalManager.fan_speed[6])
+ || TERN0(HAS_FAN7, thermalManager.fan_speed[7])
+ ) leds |= LED_C;
+ #endif // HAS_FAN
+
+ if (TERN0(HAS_MULTI_HOTEND, thermalManager.degTargetHotend(1) > 0)) leds |= LED_C;
+
+ if (leds != ledsprev) {
+ lcd.setBacklight(leds);
+ ledsprev = leds;
+ }
+ }
+
+ #endif // LCD_HAS_STATUS_INDICATORS
+
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
+
+ #define HD44780_CHAR_WIDTH 5
+ #define HD44780_CHAR_HEIGHT 8
+ #define MESH_MAP_COLS 7
+ #define MESH_MAP_ROWS 4
+
+ #define CHAR_LINE_TOP 0
+ #define CHAR_LINE_BOT 1
+ #define CHAR_EDGE_L 2
+ #define CHAR_EDGE_R 3
+ #define CHAR_UL_UL 4
+ #define CHAR_LR_UL 5
+ #define CHAR_UL_LR 6
+ #define CHAR_LR_LR 7
+
+ #define TOP_LEFT _BV(0)
+ #define TOP_RIGHT _BV(1)
+ #define LOWER_LEFT _BV(2)
+ #define LOWER_RIGHT _BV(3)
+
+ /**
+ * Possible map screens:
+ *
+ * 16x2 |X000.00 Y000.00|
+ * |(00,00) Z00.000|
+ *
+ * 20x2 | X:000.00 Y:000.00 |
+ * | (00,00) Z:00.000 |
+ *
+ * 16x4 |+-------+(00,00)|
+ * || |X000.00|
+ * || |Y000.00|
+ * |+-------+Z00.000|
+ *
+ * 20x4 | +-------+ (00,00) |
+ * | | | X:000.00|
+ * | | | Y:000.00|
+ * | +-------+ Z:00.000|
+ */
+
+ typedef struct {
+ uint8_t custom_char_bits[HD44780_CHAR_HEIGHT];
+ } custom_char;
+
+ typedef struct {
+ lcd_uint_t column, row,
+ x_pixel_offset, y_pixel_offset;
+ uint8_t x_pixel_mask;
+ } coordinate;
+
+ void add_edges_to_custom_char(custom_char &custom, const coordinate &ul, const coordinate &lr, const coordinate &brc, const uint8_t cell_location);
+ FORCE_INLINE static void clear_custom_char(custom_char * const cc) { ZERO(cc->custom_char_bits); }
+
+ coordinate pixel_location(int16_t x, int16_t y) {
+ coordinate ret_val;
+ int16_t xp, yp, r, c;
+
+ x++; y++; // +1 because lines on the left and top
+
+ c = x / (HD44780_CHAR_WIDTH);
+ r = y / (HD44780_CHAR_HEIGHT);
+
+ ret_val.column = c;
+ ret_val.row = r;
+
+ xp = x - c * (HD44780_CHAR_WIDTH); // Get the pixel offsets into the character cell
+ xp = HD44780_CHAR_WIDTH - 1 - xp; // Column within relevant character cell (0 on the right)
+ yp = y - r * (HD44780_CHAR_HEIGHT);
+
+ ret_val.x_pixel_mask = _BV(xp);
+ ret_val.x_pixel_offset = xp;
+ ret_val.y_pixel_offset = yp;
+ return ret_val;
+ }
+
+ inline coordinate pixel_location(const lcd_uint_t x, const lcd_uint_t y) { return pixel_location((int16_t)x, (int16_t)y); }
+
+ void prep_and_put_map_char(custom_char &chrdata, const coordinate &ul, const coordinate &lr, const coordinate &brc, const uint8_t cl, const char c, const lcd_uint_t x, const lcd_uint_t y) {
+ add_edges_to_custom_char(chrdata, ul, lr, brc, cl);
+ lcd.createChar(c, (uint8_t*)&chrdata);
+ lcd_put_lchar(x, y, c);
+ }
+
+ void MarlinUI::ubl_plot(const uint8_t x_plot, const uint8_t y_plot) {
+
+ #if LCD_WIDTH >= 20
+ #define _LCD_W_POS 12
+ #define _PLOT_X 1
+ #define _MAP_X 3
+ #define _LABEL(C,X,Y) lcd_put_u8str_P(X, Y, C)
+ #define _XLABEL(X,Y) _LABEL(X_LBL,X,Y)
+ #define _YLABEL(X,Y) _LABEL(Y_LBL,X,Y)
+ #define _ZLABEL(X,Y) _LABEL(Z_LBL,X,Y)
+ #else
+ #define _LCD_W_POS 8
+ #define _PLOT_X 0
+ #define _MAP_X 1
+ #define _LABEL(X,Y,C) lcd_put_lchar(X, Y, C)
+ #define _XLABEL(X,Y) _LABEL('X',X,Y)
+ #define _YLABEL(X,Y) _LABEL('Y',X,Y)
+ #define _ZLABEL(X,Y) _LABEL('Z',X,Y)
+ #endif
+
+ #if LCD_HEIGHT <= 3 // 16x2 or 20x2 display
+
+ /**
+ * Show X and Y positions
+ */
+ _XLABEL(_PLOT_X, 0);
+ lcd_put_u8str(ftostr52(LOGICAL_X_POSITION(bedlevel.get_mesh_x(x_plot))));
+ _YLABEL(_LCD_W_POS, 0);
+ lcd_put_u8str(ftostr52(LOGICAL_Y_POSITION(bedlevel.get_mesh_y(y_plot))));
+
+ lcd_moveto(_PLOT_X, 0);
+
+ #else // 16x4 or 20x4 display
+
+ coordinate upper_left, lower_right, bottom_right_corner;
+ custom_char new_char;
+ uint8_t i, n, n_rows, n_cols;
+ lcd_uint_t j, k, l, m, bottom_line, right_edge,
+ x_map_pixels, y_map_pixels,
+ pixels_per_x_mesh_pnt, pixels_per_y_mesh_pnt,
+ suppress_x_offset = 0, suppress_y_offset = 0;
+
+ const uint8_t y_plot_inv = (GRID_MAX_POINTS_Y) - 1 - y_plot;
+
+ upper_left.column = 0;
+ upper_left.row = 0;
+ lower_right.column = 0;
+ lower_right.row = 0;
+
+ clear_lcd();
+
+ x_map_pixels = (HD44780_CHAR_WIDTH) * (MESH_MAP_COLS) - 2; // Minus 2 because we are drawing a box around the map
+ y_map_pixels = (HD44780_CHAR_HEIGHT) * (MESH_MAP_ROWS) - 2;
+
+ pixels_per_x_mesh_pnt = x_map_pixels / (GRID_MAX_POINTS_X);
+ pixels_per_y_mesh_pnt = y_map_pixels / (GRID_MAX_POINTS_Y);
+
+ if (pixels_per_x_mesh_pnt >= HD44780_CHAR_WIDTH) { // There are only 2 custom characters available, so the X
+ pixels_per_x_mesh_pnt = HD44780_CHAR_WIDTH; // Size of the mesh point needs to fit within them independent
+ suppress_x_offset = 1; // Of where the starting pixel is located.
+ }
+
+ if (pixels_per_y_mesh_pnt >= HD44780_CHAR_HEIGHT) { // There are only 2 custom characters available, so the Y
+ pixels_per_y_mesh_pnt = HD44780_CHAR_HEIGHT; // Size of the mesh point needs to fit within them independent
+ suppress_y_offset = 1; // Of where the starting pixel is located.
+ }
+
+ x_map_pixels = pixels_per_x_mesh_pnt * (GRID_MAX_POINTS_X); // Now we have the right number of pixels to make both
+ y_map_pixels = pixels_per_y_mesh_pnt * (GRID_MAX_POINTS_Y); // Directions fit nicely
+
+ right_edge = pixels_per_x_mesh_pnt * (GRID_MAX_POINTS_X) + 1; // Find location of right edge within the character cell
+ bottom_line = pixels_per_y_mesh_pnt * (GRID_MAX_POINTS_Y) + 1; // Find location of bottom line within the character cell
+
+ n_rows = bottom_line / (HD44780_CHAR_HEIGHT) + 1;
+ n_cols = right_edge / (HD44780_CHAR_WIDTH) + 1;
+
+ for (i = 0; i < n_cols; i++) {
+ lcd_put_lchar(i, 0, CHAR_LINE_TOP); // Box Top line
+ lcd_put_lchar(i, n_rows - 1, CHAR_LINE_BOT); // Box Bottom line
+ }
+
+ for (j = 0; j < n_rows; j++) {
+ lcd_put_lchar(0, j, CHAR_EDGE_L); // Box Left edge
+ lcd_put_lchar(n_cols - 1, j, CHAR_EDGE_R); // Box Right edge
+ }
+
+ /**
+ * If the entire 4th row is not in use, do not put vertical bars all the way down to the bottom of the display
+ */
+
+ k = pixels_per_y_mesh_pnt * (GRID_MAX_POINTS_Y) + 2;
+ l = (HD44780_CHAR_HEIGHT) * n_rows;
+ if (l > k && l - k >= (HD44780_CHAR_HEIGHT) / 2) {
+ lcd_put_lchar(0, n_rows - 1, ' '); // Box Left edge
+ lcd_put_lchar(n_cols - 1, n_rows - 1, ' '); // Box Right edge
+ }
+
+ clear_custom_char(&new_char);
+ new_char.custom_char_bits[0] = 0b11111U; // Char #0 is used for the box top line
+ lcd.createChar(CHAR_LINE_TOP, (uint8_t*)&new_char);
+
+ clear_custom_char(&new_char);
+ k = (GRID_MAX_POINTS_Y) * pixels_per_y_mesh_pnt + 1; // Row of pixels for the bottom box line
+ l = k % (HD44780_CHAR_HEIGHT); // Row within relevant character cell
+ new_char.custom_char_bits[l] = 0b11111U; // Char #1 is used for the box bottom line
+ lcd.createChar(CHAR_LINE_BOT, (uint8_t*)&new_char);
+
+ clear_custom_char(&new_char);
+ for (j = 0; j < HD44780_CHAR_HEIGHT; j++)
+ new_char.custom_char_bits[j] = 0b10000U; // Char #2 is used for the box left edge
+ lcd.createChar(CHAR_EDGE_L, (uint8_t*)&new_char);
+
+ clear_custom_char(&new_char);
+ m = (GRID_MAX_POINTS_X) * pixels_per_x_mesh_pnt + 1; // Column of pixels for the right box line
+ n = m % (HD44780_CHAR_WIDTH); // Column within relevant character cell
+ i = HD44780_CHAR_WIDTH - 1 - n; // Column within relevant character cell (0 on the right)
+ for (j = 0; j < HD44780_CHAR_HEIGHT; j++)
+ new_char.custom_char_bits[j] = (uint8_t)_BV(i); // Char #3 is used for the box right edge
+ lcd.createChar(CHAR_EDGE_R, (uint8_t*)&new_char);
+
+ i = x_plot * pixels_per_x_mesh_pnt - suppress_x_offset;
+ j = y_plot_inv * pixels_per_y_mesh_pnt - suppress_y_offset;
+ upper_left = pixel_location(i, j);
+
+ k = (x_plot + 1) * pixels_per_x_mesh_pnt - 1 - suppress_x_offset;
+ l = (y_plot_inv + 1) * pixels_per_y_mesh_pnt - 1 - suppress_y_offset;
+ lower_right = pixel_location(k, l);
+
+ bottom_right_corner = pixel_location(x_map_pixels, y_map_pixels);
+
+ /**
+ * First, handle the simple case where everything is within a single character cell.
+ * If part of the Mesh Plot is outside of this character cell, we will follow up
+ * and deal with that next.
+ */
+
+ clear_custom_char(&new_char);
+ const lcd_uint_t ypix = _MIN(upper_left.y_pixel_offset + pixels_per_y_mesh_pnt, HD44780_CHAR_HEIGHT);
+ for (j = upper_left.y_pixel_offset; j < ypix; j++) {
+ i = upper_left.x_pixel_mask;
+ for (k = 0; k < pixels_per_x_mesh_pnt; k++) {
+ new_char.custom_char_bits[j] |= i;
+ i >>= 1;
+ }
+ }
+
+ prep_and_put_map_char(new_char, upper_left, lower_right, bottom_right_corner, TOP_LEFT, CHAR_UL_UL, upper_left.column, upper_left.row);
+
+ /**
+ * Next, check for two side by side character cells being used to display the Mesh Point
+ * If found... do the right hand character cell next.
+ */
+ if (upper_left.column == lower_right.column - 1) {
+ l = upper_left.x_pixel_offset;
+ clear_custom_char(&new_char);
+ for (j = upper_left.y_pixel_offset; j < ypix; j++) {
+ i = _BV(HD44780_CHAR_WIDTH - 1); // Fill in the left side of the right character cell
+ for (k = 0; k < pixels_per_x_mesh_pnt - 1 - l; k++) {
+ new_char.custom_char_bits[j] |= i;
+ i >>= 1;
+ }
+ }
+ prep_and_put_map_char(new_char, upper_left, lower_right, bottom_right_corner, TOP_RIGHT, CHAR_LR_UL, lower_right.column, upper_left.row);
+ }
+
+ /**
+ * Next, check for two character cells stacked on top of each other being used to display the Mesh Point
+ */
+ if (upper_left.row == lower_right.row - 1) {
+ l = HD44780_CHAR_HEIGHT - upper_left.y_pixel_offset; // Number of pixel rows in top character cell
+ k = pixels_per_y_mesh_pnt - l; // Number of pixel rows in bottom character cell
+ clear_custom_char(&new_char);
+ for (j = 0; j < k; j++) {
+ i = upper_left.x_pixel_mask;
+ for (m = 0; m < pixels_per_x_mesh_pnt; m++) { // Fill in the top side of the bottom character cell
+ new_char.custom_char_bits[j] |= i;
+ if (!(i >>= 1)) break;
+ }
+ }
+ prep_and_put_map_char(new_char, upper_left, lower_right, bottom_right_corner, LOWER_LEFT, CHAR_UL_LR, upper_left.column, lower_right.row);
+ }
+
+ /**
+ * Next, check for four character cells being used to display the Mesh Point. If that is
+ * what is here, we work to fill in the character cell that is down one and to the right one
+ * from the upper_left character cell.
+ */
+
+ if (upper_left.column == lower_right.column - 1 && upper_left.row == lower_right.row - 1) {
+ l = HD44780_CHAR_HEIGHT - upper_left.y_pixel_offset; // Number of pixel rows in top character cell
+ k = pixels_per_y_mesh_pnt - l; // Number of pixel rows in bottom character cell
+ clear_custom_char(&new_char);
+ for (j = 0; j < k; j++) {
+ l = upper_left.x_pixel_offset;
+ i = _BV(HD44780_CHAR_WIDTH - 1); // Fill in the left side of the right character cell
+ for (m = 0; m < pixels_per_x_mesh_pnt - 1 - l; m++) { // Fill in the top side of the bottom character cell
+ new_char.custom_char_bits[j] |= i;
+ i >>= 1;
+ }
+ }
+ prep_and_put_map_char(new_char, upper_left, lower_right, bottom_right_corner, LOWER_RIGHT, CHAR_LR_LR, lower_right.column, lower_right.row);
+ }
+
+ #endif
+
+ /**
+ * Print plot position
+ */
+ lcd_put_lchar(_LCD_W_POS, 0, '(');
+ lcd_put_u8str(ui8tostr3rj(x_plot));
+ lcd_put_lchar(',');
+ lcd_put_u8str(ui8tostr3rj(y_plot));
+ lcd_put_lchar(')');
+
+ #if LCD_HEIGHT <= 3 // 16x2 or 20x2 display
+
+ /**
+ * Print Z values
+ */
+ _ZLABEL(_LCD_W_POS, 1);
+ if (!isnan(bedlevel.z_values[x_plot][y_plot]))
+ lcd_put_u8str(ftostr43sign(bedlevel.z_values[x_plot][y_plot]));
+ else
+ lcd_put_u8str(F(" -----"));
+
+ #else // 16x4 or 20x4 display
+
+ /**
+ * Show all values at right of screen
+ */
+ _XLABEL(_LCD_W_POS, 1);
+ lcd_put_u8str(ftostr52(LOGICAL_X_POSITION(bedlevel.get_mesh_x(x_plot))));
+ _YLABEL(_LCD_W_POS, 2);
+ lcd_put_u8str(ftostr52(LOGICAL_Y_POSITION(bedlevel.get_mesh_y(y_plot))));
+
+ /**
+ * Show the location value
+ */
+ _ZLABEL(_LCD_W_POS, 3);
+ if (!isnan(bedlevel.z_values[x_plot][y_plot]))
+ lcd_put_u8str(ftostr43sign(bedlevel.z_values[x_plot][y_plot]));
+ else
+ lcd_put_u8str(F(" -----"));
+
+ #endif // LCD_HEIGHT > 3
+ }
+
+ void add_edges_to_custom_char(custom_char &custom, const coordinate &ul, const coordinate &lr, const coordinate &brc, const uint8_t cell_location) {
+ uint8_t i, k;
+ int16_t n_rows = lr.row - ul.row + 1,
+ n_cols = lr.column - ul.column + 1;
+
+ /**
+ * Check if Top line of box needs to be filled in
+ */
+
+ if (ul.row == 0 && (cell_location & (TOP_LEFT|TOP_RIGHT))) { // Only fill in the top line for the top character cells
+
+ if (n_cols == 1) {
+ if (ul.column != brc.column)
+ custom.custom_char_bits[0] = 0xFF; // Single column in middle
+ else
+ for (i = brc.x_pixel_offset; i < HD44780_CHAR_WIDTH; i++) // Single column on right side
+ SBI(custom.custom_char_bits[0], i);
+ }
+ else if ((cell_location & TOP_LEFT) || lr.column != brc.column) // Multiple column in the middle or with right cell in middle
+ custom.custom_char_bits[0] = 0xFF;
+ else
+ for (i = brc.x_pixel_offset; i < HD44780_CHAR_WIDTH; i++)
+ SBI(custom.custom_char_bits[0], i);
+ }
+
+ /**
+ * Check if left line of box needs to be filled in
+ */
+ if (cell_location & (TOP_LEFT|LOWER_LEFT)) {
+ if (ul.column == 0) { // Left column of characters on LCD Display
+ k = ul.row == brc.row ? brc.y_pixel_offset : HD44780_CHAR_HEIGHT; // If it isn't the last row... do the full character cell
+ for (i = 0; i < k; i++)
+ SBI(custom.custom_char_bits[i], HD44780_CHAR_WIDTH - 1);
+ }
+ }
+
+ /**
+ * Check if bottom line of box needs to be filled in
+ */
+
+ // Single row of mesh plot cells
+ if (n_rows == 1 /* && (cell_location & (TOP_LEFT|TOP_RIGHT)) */ && ul.row == brc.row) {
+ if (n_cols == 1) // Single row, single column case
+ k = ul.column == brc.column ? brc.x_pixel_mask : 0x01;
+ else if (cell_location & TOP_RIGHT) // Single row, multiple column case
+ k = lr.column == brc.column ? brc.x_pixel_mask : 0x01;
+ else // Single row, left of multiple columns
+ k = 0x01;
+ while (k < _BV(HD44780_CHAR_WIDTH)) {
+ custom.custom_char_bits[brc.y_pixel_offset] |= k;
+ k <<= 1;
+ }
+ }
+
+ // Double row of characters on LCD Display
+ // And this is a bottom custom character
+ if (n_rows == 2 && (cell_location & (LOWER_LEFT|LOWER_RIGHT)) && lr.row == brc.row) {
+ if (n_cols == 1) // Double row, single column case
+ k = ul.column == brc.column ? brc.x_pixel_mask : 0x01;
+ else if (cell_location & LOWER_RIGHT) // Double row, multiple column case
+ k = lr.column == brc.column ? brc.x_pixel_mask : 0x01;
+ else // Double row, left of multiple columns
+ k = 0x01;
+ while (k < _BV(HD44780_CHAR_WIDTH)) {
+ custom.custom_char_bits[brc.y_pixel_offset] |= k;
+ k <<= 1;
+ }
+ }
+
+ /**
+ * Check if right line of box needs to be filled in
+ */
+
+ // Nothing to do if the lower right part of the mesh pnt isn't in the same column as the box line
+ if (lr.column == brc.column) {
+ // This mesh point is in the same character cell as the right box line
+ if (ul.column == brc.column || (cell_location & (TOP_RIGHT|LOWER_RIGHT))) {
+ // If not the last row... do the full character cell
+ k = ul.row == brc.row ? brc.y_pixel_offset : HD44780_CHAR_HEIGHT;
+ for (i = 0; i < k; i++) custom.custom_char_bits[i] |= brc.x_pixel_mask;
+ }
+ }
+ }
+
+ #endif // AUTO_BED_LEVELING_UBL
+
+#endif // HAS_MARLINUI_MENU
+
+#endif // HAS_MARLINUI_HD44780
diff --git a/src/lcd/HD44780/marlinui_HD44780.h b/src/lcd/HD44780/marlinui_HD44780.h
new file mode 100644
index 0000000..62c0c76
--- /dev/null
+++ b/src/lcd/HD44780/marlinui_HD44780.h
@@ -0,0 +1,107 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+/**
+ * Hitachi HD44780 display defines and headers
+ */
+
+#include "../../inc/MarlinConfig.h"
+
+#if ENABLED(LCD_I2C_TYPE_PCF8575)
+
+ // NOTE: These are register-mapped pins on the PCF8575 controller, not Arduino pins.
+ #define LCD_I2C_PIN_BL 3
+ #define LCD_I2C_PIN_EN 2
+ #define LCD_I2C_PIN_RW 1
+ #define LCD_I2C_PIN_RS 0
+ #define LCD_I2C_PIN_D4 4
+ #define LCD_I2C_PIN_D5 5
+ #define LCD_I2C_PIN_D6 6
+ #define LCD_I2C_PIN_D7 7
+
+ #include
+ #include
+ #include
+ #define LCD_CLASS LiquidCrystal_I2C
+
+#elif ENABLED(LCD_I2C_TYPE_MCP23017)
+
+ // For the LED indicators (which may be mapped to different events in update_indicators())
+ #define LCD_HAS_STATUS_INDICATORS
+ #define LED_A 0x04 //100
+ #define LED_B 0x02 //010
+ #define LED_C 0x01 //001
+
+ #include
+ #include
+ #define LCD_CLASS LiquidTWI2
+
+#elif ENABLED(LCD_I2C_TYPE_MCP23008)
+
+ #include
+ #include
+ #define LCD_CLASS LiquidTWI2
+
+#elif ENABLED(LCD_I2C_TYPE_PCA8574)
+
+ #include
+ #define LCD_CLASS LiquidCrystal_I2C
+
+#elif ENABLED(SR_LCD_2W_NL)
+
+ // 2 wire Non-latching LCD SR from:
+ // https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/schematics#!shiftregister-connection
+ #include
+ #include
+ #define LCD_CLASS LiquidCrystal_SR
+
+#elif ENABLED(SR_LCD_3W_NL)
+
+ // NewLiquidCrystal didn't work, so this uses
+ // https://github.com/mikeshub/SailfishLCD
+
+ #include
+ #define LCD_CLASS LiquidCrystalSerial
+
+#elif ENABLED(LCM1602)
+
+ #include
+ #include
+ #include
+ #define LCD_CLASS LiquidCrystal_I2C
+
+#elif ENABLED(YHCB2004)
+
+ #include
+ #define LCD_CLASS LiquidCrystal_AIP31068_SPI
+
+#else
+
+ // Standard directly connected LCD implementations
+ #include
+ #define LCD_CLASS LiquidCrystal
+
+#endif
+
+#include "../fontutils.h"
+#include "../lcdprint.h"
diff --git a/src/lcd/extui/anycubic_chiron/FileNavigator.cpp b/src/lcd/extui/anycubic_chiron/FileNavigator.cpp
new file mode 100644
index 0000000..0ef8186
--- /dev/null
+++ b/src/lcd/extui/anycubic_chiron/FileNavigator.cpp
@@ -0,0 +1,258 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/**
+ * lcd/extui/anycubic_chiron/FileNavigator.cpp
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ *
+ * The AC panel wants files in block of 4 and can only display a flat list
+ * This library allows full folder traversal or flat file display and supports both standerd and new style panels.
+ *
+ * ## Old Style TFT panel
+ * Supported chars {}[]-+=_"$%^&*()~<>|
+ * Max display length 22 chars
+ * Max path len 29 chars
+ * (DOS 8.3 filepath max 29chars)
+ * (long filepath Max 22)
+ *
+ * ## New TFT Panel Format file display format
+ * Supported chars {}[]-+=_!"$%^&*()~<>\|
+ * Max display length 26 chars
+ * Max path len 29 chars
+ * (DOS 8.3 filepath must end '.GCO')
+ * (long filepath must end '.gcode')
+ *
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
+#include "FileNavigator.h"
+#include "chiron_tft.h"
+
+using namespace ExtUI;
+
+#define DEBUG_OUT ACDEBUG(AC_FILE)
+#include "../../../core/debug_out.h"
+
+namespace Anycubic {
+
+FileNavigator filenavigator;
+FileList FileNavigator::filelist; // Instance of the Marlin file API
+uint16_t FileNavigator::lastpanelindex;
+uint16_t FileNavigator::currentindex; // override the panel request
+uint8_t FileNavigator::currentfolderdepth;
+uint16_t FileNavigator::currentfolderindex[MAX_FOLDER_DEPTH]; // track folder pos for iteration
+char FileNavigator::currentfoldername[MAX_PATH_LEN + 1]; // Current folder path
+
+FileNavigator::FileNavigator() { reset(); }
+
+void FileNavigator::reset() {
+ DEBUG_ECHOLNPGM("reset()");
+ currentfoldername[0] = '\0';
+ currentfolderdepth = 0;
+ currentindex = 0;
+ lastpanelindex = 0;
+ ZERO(currentfolderindex);
+
+ // Start at root folder
+ while (!filelist.isAtRootDir()) filelist.upDir();
+ refresh();
+}
+
+void FileNavigator::refresh() { filelist.refresh(); }
+
+void FileNavigator::changeDIR(const char *folder) {
+ if (currentfolderdepth >= MAX_FOLDER_DEPTH) return; // limit the folder depth
+ DEBUG_ECHOLNPGM("FD:" , folderdepth, " FP:",currentindex, " currentfolder:", currentfoldername, " enter:", folder);
+ currentfolderindex[currentfolderdepth] = currentindex;
+ strcat(currentfoldername, folder);
+ strcat(currentfoldername, "/");
+ filelist.changeDir(folder);
+ currentfolderdepth++;
+ currentindex = 0;
+}
+
+void FileNavigator::upDIR() {
+ DEBUG_ECHOLNPGM("upDIR() from D:", currentfolderdepth, " N:", currentfoldername);
+ if (!filelist.isAtRootDir()) {
+ filelist.upDir();
+ currentfolderdepth--;
+ currentindex = currentfolderindex[currentfolderdepth]; // restore last position in the folder
+ filelist.seek(currentindex); // restore file information
+ }
+
+ // Remove the child folder from the stored path
+ if (currentfolderdepth == 0)
+ currentfoldername[0] = '\0';
+ else {
+ char * const pos = strchr(currentfoldername, '/');
+ *(pos + 1) = '\0';
+ }
+}
+
+void FileNavigator::skiptofileindex(uint16_t skip) {
+ if (skip == 0) return;
+ while (skip > 0) {
+ if (filelist.seek(currentindex)) {
+ DEBUG_ECHOLNPGM("CI:", currentindex, " FD:", currentfolderdepth, " N:", skip, " ", filelist.longFilename());
+ if (!filelist.isDir()) {
+ skip--;
+ currentindex++;
+ }
+ else
+ changeDIR(filelist.shortFilename());
+ } // valid file
+ if (currentindex == filelist.count()) {
+ if (currentfolderdepth > 0) {
+ upDIR();
+ currentindex++;
+ }
+ else break; // end of root folder
+ } // end of folder
+ } // files needed
+ // No more files available.
+}
+
+#if ENABLED(AC_SD_FOLDER_VIEW) // SD Folder navigation
+
+ void FileNavigator::getFiles(uint16_t index, panel_type_t paneltype, uint8_t filesneeded) {
+ if (index == 0) currentindex = 0;
+ // Each time we change folder we reset the file index to 0 and keep track
+ // of the current position, since the TFT panel isn't aware of folder trees.
+ if (index > 0) {
+ --currentindex; // go back a file to take account of the .. we added to the root.
+ if (index > lastpanelindex)
+ currentindex += filesneeded;
+ else
+ currentindex = currentindex < 4 ? 0 : currentindex - filesneeded;
+ }
+ lastpanelindex = index;
+
+ DEBUG_ECHOLNPGM("index=", index, " currentindex=", currentindex);
+
+ if (currentindex == 0 && currentfolderdepth > 0) { // Add a link to go up a folder
+ // The new panel ignores entries that don't end in .GCO or .gcode so add and pad them.
+ if (paneltype <= AC_panel_new) {
+ TFTSer.println("<<.GCO");
+ Chiron.SendtoTFTLN(F(".. .gcode"));
+ }
+ else {
+ TFTSer.println("<<");
+ TFTSer.println("..");
+ }
+ filesneeded--;
+ }
+
+ for (uint16_t seek = currentindex; seek < currentindex + filesneeded; seek++) {
+ if (filelist.seek(seek)) {
+ sendFile(paneltype);
+ DEBUG_ECHOLNPGM("-", seek, " '", filelist.longFilename(), "' '", currentfoldername, "", filelist.shortFilename(), "'");
+ }
+ }
+ }
+
+ void FileNavigator::sendFile(panel_type_t paneltype) {
+ if (filelist.isDir()) {
+ // Add mandatory tags for new panel otherwise lines are ignored.
+ if (paneltype <= AC_panel_new) {
+ TFTSer.print(filelist.shortFilename());
+ TFTSer.println(".GCO");
+ TFTSer.print(filelist.shortFilename());
+ TFTSer.write('/');
+ // Make sure we fill all 29 chars of the display line to clear the text buffer otherwise the last line is still visible
+ for (int8_t i = strlen(filelist.shortFilename()); i < 19; i++)
+ TFTSer.write(' ');
+ TFTSer.println(".gcode");
+ }
+ else {
+ TFTSer.println(filelist.shortFilename());
+ TFTSer.print(filelist.shortFilename());
+ TFTSer.write('/');
+ TFTSer.println();
+ }
+ }
+ else { // Not DIR
+ TFTSer.write('/');
+ if (currentfolderdepth > 0) TFTSer.print(currentfoldername);
+ TFTSer.println(filelist.shortFilename());
+ TFTSer.print(filelist.longFilename());
+
+ // Make sure we fill all 29 chars of the display line to clear the text buffer otherwise the last line is still visible
+ if (paneltype == AC_panel_new)
+ for (int8_t i = strlen(filelist.longFilename()); i < 26; i++)
+ TFTSer.write(' ');
+
+ TFTSer.println();
+ }
+ } // AC_SD_FOLDER_VIEW
+
+#else // Flat file list
+
+ void FileNavigator::getFiles(uint16_t index, panel_type_t paneltype, uint8_t filesneeded) {
+ DEBUG_ECHOLNPGM("getFiles() I:", index," L:", lastpanelindex);
+ // if we're searching backwards, jump back to start and search forward
+ if (index < lastpanelindex) {
+ reset();
+ skiptofileindex(index);
+ }
+ lastpanelindex = index;
+
+ while (filesneeded > 0) {
+ if (filelist.seek(currentindex)) {
+ if (!filelist.isDir()) {
+ sendFile(paneltype);
+ filesneeded--;
+ currentindex++;
+ }
+ else
+ changeDIR(filelist.shortFilename());
+ } // valid file
+
+ if (currentindex == filelist.count()) {
+ if (currentfolderdepth > 0) {
+ upDIR();
+ currentindex++;
+ }
+ else break; // end of root folder
+ } // end of folder
+ } // files needed
+ // No more files available.
+ }
+
+ void FileNavigator::sendFile(panel_type_t paneltype) {
+ TFTSer.write('/');
+ if (currentfolderdepth > 0) TFTSer.print(currentfoldername);
+ TFTSer.println(filelist.shortFilename());
+ if (currentfolderdepth > 0) TFTSer.print(currentfoldername);
+ TFTSer.println(filelist.longFilename());
+ DEBUG_ECHOLNPGM("/", currentfoldername, "", filelist.shortFilename(), " ", filelist.longFilename());
+ }
+
+#endif // Flat file list
+
+} // Anycubic namespace
+
+#endif // ANYCUBIC_LCD_CHIRON
diff --git a/src/lcd/extui/anycubic_chiron/FileNavigator.h b/src/lcd/extui/anycubic_chiron/FileNavigator.h
new file mode 100644
index 0000000..ca4283f
--- /dev/null
+++ b/src/lcd/extui/anycubic_chiron/FileNavigator.h
@@ -0,0 +1,61 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/anycubic_chiron/FileNavigator.h
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+#include "chiron_tft_defs.h"
+#include "../ui_api.h"
+
+using namespace ExtUI;
+
+namespace Anycubic {
+
+class FileNavigator {
+ public:
+ FileNavigator();
+ static void reset();
+ static void getFiles(uint16_t, panel_type_t, uint8_t filesneeded=4);
+ static void upDIR();
+ static void changeDIR(const char *);
+ static void sendFile(panel_type_t);
+ static void refresh();
+ static void skiptofileindex(uint16_t);
+
+ static FileList filelist;
+ private:
+ static uint16_t lastpanelindex;
+ static uint16_t currentindex;
+ static uint8_t currentfolderdepth;
+ static uint16_t currentfolderindex[MAX_FOLDER_DEPTH];
+ static char currentfoldername[MAX_PATH_LEN + 1];
+};
+
+extern FileNavigator filenavigator;
+
+}
diff --git a/src/lcd/extui/anycubic_chiron/Tunes.cpp b/src/lcd/extui/anycubic_chiron/Tunes.cpp
new file mode 100644
index 0000000..adbf98e
--- /dev/null
+++ b/src/lcd/extui/anycubic_chiron/Tunes.cpp
@@ -0,0 +1,61 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/**
+ * lcd/extui/anycubic_chiron/Tunes.cpp
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+/***********************************************************************
+ * A Utility to play tunes using the buzzer in the printer controller. *
+ * See Tunes.h for note and tune definitions. *
+ ***********************************************************************/
+
+#include "../../../inc/MarlinConfigPre.h"
+
+// TODO: Use Marlin's built-in tone player instead.
+
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
+
+#include "Tunes.h"
+#include "../ui_api.h"
+
+namespace Anycubic {
+
+ void PlayTune(uint8_t beeperPin, const uint16_t *tune, uint8_t speed=1) {
+ uint8_t pos = 1;
+ const uint16_t wholenotelen = tune[0] / speed;
+ do {
+ const uint16_t freq = tune[pos], notelen = wholenotelen / tune[pos + 1];
+ ::tone(beeperPin, freq, notelen);
+ ExtUI::delay_ms(notelen);
+ pos += 2;
+ if (pos >= MAX_TUNE_LENGTH) break;
+ } while (tune[pos] != n_END);
+ }
+
+}
+
+#endif // ANYCUBIC_LCD_CHIRON
diff --git a/src/lcd/extui/anycubic_chiron/Tunes.h b/src/lcd/extui/anycubic_chiron/Tunes.h
new file mode 100644
index 0000000..bf2e92d
--- /dev/null
+++ b/src/lcd/extui/anycubic_chiron/Tunes.h
@@ -0,0 +1,224 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/anycubic_chiron/Tunes.h
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+/**************************************************************************
+ * Notes definition from https://pages.mtu.edu/~suits/NoteFreqCalcs.html *
+ * *
+ * The format of a tune is: *
+ * {,,, ,, ... } *
+ * *
+ * 1) The first value is the length of a whole note in milliseconds *
+ * 2) Then a sequence of pitch and duration pairs *
+ * 3) Finally the END marker so your tunes can be any length up to *
+ * MAX_TUNE_LEN *
+ *************************************************************************/
+
+#include
+
+#define MAX_TUNE_LENGTH 128
+
+// Special notes!
+#define n_P 0 // silence or pause
+#define n_END 10000 // end of tune marker
+
+// Note duration divisors
+#define l_T1 1
+#define l_T2 2
+#define l_T3 3
+#define l_T4 4
+#define l_T8 8
+#define l_T16 16
+
+// Note Frequency
+#define n_C0 16
+#define n_CS0 17
+#define n_D0 18
+#define n_DS0 19
+#define n_E0 21
+#define n_F0 22
+#define n_FS0 23
+#define n_G0 25
+#define n_GS0 26
+#define n_A0 28
+#define n_AS0 29
+#define n_B0 31
+#define n_C1 33
+#define n_CS1 35
+#define n_D1 37
+#define n_DS1 39
+#define n_E1 41
+#define n_F1 44
+#define n_FS1 46
+#define n_G1 49
+#define n_GS1 52
+#define n_A1 55
+#define n_AS1 58
+#define n_B1 62
+#define n_C2 65
+#define n_CS2 69
+#define n_D2 73
+#define n_DS2 78
+#define n_E2 82
+#define n_F2 87
+#define n_FS2 93
+#define n_G2 98
+#define n_GS2 104
+#define n_A2 110
+#define n_AS2 117
+#define n_B2 123
+#define n_C3 131
+#define n_CS3 139
+#define n_D3 147
+#define n_DS3 156
+#define n_E3 165
+#define n_F3 175
+#define n_FS3 185
+#define n_G3 196
+#define n_GS3 208
+#define n_A3 220
+#define n_AS3 233
+#define n_B3 247
+#define n_C4 262
+#define n_CS4 277
+#define n_D4 294
+#define n_DS4 311
+#define n_E4 330
+#define n_F4 349
+#define n_FS4 370
+#define n_G4 392
+#define n_GS4 415
+#define n_A4 440
+#define n_AS4 466
+#define n_B4 494
+#define n_C5 523
+#define n_CS5 554
+#define n_D5 587
+#define n_DS5 622
+#define n_E5 659
+#define n_F5 698
+#define n_FS5 740
+#define n_G5 784
+#define n_GS5 831
+#define n_A5 880
+#define n_AS5 932
+#define n_B5 988
+#define n_C6 1047
+#define n_CS6 1109
+#define n_D6 1175
+#define n_DS6 1245
+#define n_E6 1319
+#define n_F6 1397
+#define n_FS6 1480
+#define n_G6 1568
+#define n_GS6 1661
+#define n_A6 1760
+#define n_AS6 1865
+#define n_B6 1976
+#define n_C7 2093
+#define n_CS7 2217
+#define n_D7 2349
+#define n_DS7 2489
+#define n_E7 2637
+#define n_F7 2794
+#define n_FS7 2960
+#define n_G7 3136
+#define n_GS7 3322
+#define n_A7 3520
+#define n_AS7 3729
+#define n_B7 3951
+#define n_C8 4186
+#define n_CS8 4435
+#define n_D8 4699
+#define n_DS8 4978
+#define n_E8 5274
+#define n_F8 5587
+#define n_FS8 5920
+#define n_G8 6272
+#define n_GS8 6645
+#define n_A8 7040
+#define n_AS8 7459
+#define n_B8 7902
+
+namespace Anycubic {
+
+ void PlayTune(uint8_t beeperPin, const uint16_t *tune, uint8_t speed);
+
+ // Only uncomment the tunes you are using to save memory
+ // This will help you write tunes!
+ // https://www.apronus.com/music/flashpiano.htm
+
+ const uint16_t SOS[] = {
+ 250,
+ n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T1,
+ n_G6,l_T1, n_P,l_T3, n_G6,l_T1, n_P,l_T3, n_G6,l_T1, n_P,l_T1,
+ n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T3, n_G6,l_T3, n_P,l_T1,
+ n_END
+ };
+
+ const uint16_t BeepBeep[] = {
+ 500,
+ n_C7,l_T8, n_P,l_T16, n_C7,l_T8, n_P,l_T8,
+ n_END
+ };
+
+ const uint16_t BeepBeepBeeep[] = {
+ 1000,
+ n_G7,l_T4, n_P,l_T16, n_G7,l_T4, n_P,l_T8, n_G7,l_T2,
+ n_END
+ };
+
+ const uint16_t Anycubic_PowerOn[] = {
+ 1000,
+ n_F7,l_T8, n_P,l_T8, n_C7,l_T8, n_P,l_T8, n_D7,l_T8, n_P,l_T8,
+ n_E7,l_T8, n_P,l_T8, n_D7,l_T4, n_P,l_T4, n_G7,l_T4, n_P,l_T4,
+ n_A7,l_T2, n_P,l_T1,
+ n_END
+ };
+
+ const uint16_t GB_PowerOn[] = {
+ 500,
+ n_C6,l_T4, n_P,l_T16, n_C7,l_T2, n_P,l_T8,
+ n_END
+ };
+
+ const uint16_t Heater_Timedout[] = {
+ 1000,
+ n_C6,l_T1,
+ n_END
+ };
+
+ const uint16_t FilamentOut[] = {
+ 1000,
+ n_AS7,l_T4, n_P,l_T16, n_FS7,l_T2,
+ n_END
+ };
+
+}
diff --git a/src/lcd/extui/anycubic_chiron/chiron_extui.cpp b/src/lcd/extui/anycubic_chiron/chiron_extui.cpp
new file mode 100644
index 0000000..75061c1
--- /dev/null
+++ b/src/lcd/extui/anycubic_chiron/chiron_extui.cpp
@@ -0,0 +1,137 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/**
+ * lcd/extui/anycubic_chiron/chiron_extui.cpp
+ *
+ * Anycubic Chiron TFT support for Marlin
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
+
+#include "../ui_api.h"
+#include "chiron_tft.h"
+
+using namespace Anycubic;
+
+namespace ExtUI {
+
+ void onStartup() { Chiron.Startup(); }
+
+ void onIdle() { Chiron.IdleLoop(); }
+
+ void onPrinterKilled(FSTR_P const error, FSTR_P const component) {
+ Chiron.PrinterKilled(error, component);
+ }
+
+ void onMediaInserted() { Chiron.MediaEvent(AC_media_inserted); }
+ void onMediaError() { Chiron.MediaEvent(AC_media_error); }
+ void onMediaRemoved() { Chiron.MediaEvent(AC_media_removed); }
+
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {
+ #if ENABLED(SPEAKER)
+ ::tone(BEEPER_PIN, frequency, duration);
+ #endif
+ }
+
+ void onPrintTimerStarted() { Chiron.TimerEvent(AC_timer_started); }
+ void onPrintTimerPaused() { Chiron.TimerEvent(AC_timer_paused); }
+ void onPrintTimerStopped() { Chiron.TimerEvent(AC_timer_stopped); }
+ void onPrintDone() {}
+
+ void onFilamentRunout(const extruder_t) { Chiron.FilamentRunout(); }
+
+ void onUserConfirmRequired(const char * const msg) { Chiron.ConfirmationRequest(msg); }
+ void onStatusChanged(const char * const msg) { Chiron.StatusChange(msg); }
+
+ void onHomingStart() {}
+ void onHomingDone() {}
+
+ void onFactoryReset() {}
+
+ void onStoreSettings(char *buff) {
+ // Called when saving to EEPROM (i.e. M500). If the ExtUI needs
+ // permanent data to be stored, it can write up to eeprom_data_size bytes
+ // into buff.
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= eeprom_data_size);
+ // memcpy(buff, &myDataStruct, sizeof(myDataStruct));
+ }
+
+ void onLoadSettings(const char *buff) {
+ // Called while loading settings from EEPROM. If the ExtUI
+ // needs to retrieve data, it should copy up to eeprom_data_size bytes
+ // from buff
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= eeprom_data_size);
+ // memcpy(&myDataStruct, buff, sizeof(myDataStruct));
+ }
+
+ void onPostprocessSettings() {
+ // Called after loading or resetting stored settings
+ }
+
+ void onSettingsStored(bool success) {
+ // Called after the entire EEPROM has been written,
+ // whether successful or not.
+ }
+
+ void onSettingsLoaded(bool success) {
+ // Called after the entire EEPROM has been read,
+ // whether successful or not.
+ }
+
+ #if HAS_MESH
+ void onLevelingStart() {}
+ void onLevelingDone() {}
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) {
+ // Called when any mesh points are updated
+ //SERIAL_ECHOLNPGM("onMeshUpdate() x:", xpos, " y:", ypos, " z:", zval);
+ }
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const probe_state_t state) {
+ // Called to indicate a special condition
+ //SERIAL_ECHOLNPGM("onMeshUpdate() x:", xpos, " y:", ypos, " state:", state);
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ // Called on resume from power-loss
+ void onPowerLossResume() { Chiron.PowerLossRecovery(); }
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ }
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // ANYCUBIC_LCD_CHIRON
diff --git a/src/lcd/extui/anycubic_chiron/chiron_tft.cpp b/src/lcd/extui/anycubic_chiron/chiron_tft.cpp
new file mode 100644
index 0000000..285729c
--- /dev/null
+++ b/src/lcd/extui/anycubic_chiron/chiron_tft.cpp
@@ -0,0 +1,985 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/**
+ * lcd/extui/anycubic_chiron/chiron_tft.cpp
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_CHIRON)
+
+#include "chiron_tft.h"
+#include "Tunes.h"
+#include "FileNavigator.h"
+
+#include "../../../gcode/queue.h"
+#include "../../../module/stepper.h"
+#include "../../../sd/cardreader.h"
+#include "../../../libs/numtostr.h"
+#include "../../../MarlinCore.h"
+
+namespace Anycubic {
+
+ChironTFT Chiron;
+#if AUTO_DETECT_CHIRON_TFT
+ panel_type_t ChironTFT::panel_type = AC_panel_unknown;
+#endif
+last_error_t ChironTFT::last_error;
+printer_state_t ChironTFT::printer_state;
+paused_state_t ChironTFT::pause_state;
+heater_state_t ChironTFT::hotend_state;
+heater_state_t ChironTFT::hotbed_state;
+xy_uint8_t ChironTFT::selectedmeshpoint;
+char ChironTFT::selectedfile[MAX_PATH_LEN + 1];
+char ChironTFT::panel_command[MAX_CMND_LEN + 1];
+uint8_t ChironTFT::command_len;
+float ChironTFT::live_Zoffset;
+file_menu_t ChironTFT::file_menu;
+
+void ChironTFT::Startup() {
+ selectedfile[0] = '\0';
+ panel_command[0] = '\0';
+ command_len = 0;
+ last_error = AC_error_none;
+ printer_state = AC_printer_idle;
+ pause_state = AC_paused_idle;
+ hotend_state = AC_heater_off;
+ hotbed_state = AC_heater_off;
+ live_Zoffset = 0.0;
+ file_menu = AC_menu_file;
+
+ // Setup pins for powerloss detection
+ // Two IO pins are connected on the Trigorilla Board
+ // On a power interruption the OUTAGECON_PIN goes low.
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ OUT_WRITE(OUTAGECON_PIN, HIGH);
+ #endif
+
+ // Filament runout is handled by Marlin settings in Configuration.h
+ // opt_set FIL_RUNOUT_STATE HIGH // Pin state indicating that filament is NOT present.
+ // opt_enable FIL_RUNOUT_PULLUP
+ TFTSer.begin(115200);
+
+ // Wait for the TFT panel to initialize and finish the animation
+ safe_delay(1000);
+
+ // There are different panels for the Chiron with slightly different commands
+ // So we need to know what we are working with.
+ // Panel type can be defined otherwise detect it automatically
+ switch (panel_type) {
+ case AC_panel_new:
+ SERIAL_ECHOLNF(AC_msg_new_panel_set);
+ break;
+ case AC_panel_standard:
+ SERIAL_ECHOLNF(AC_msg_old_panel_set);
+ break;
+ default:
+ SERIAL_ECHOLNF(AC_msg_auto_panel_detection);
+ DetectPanelType();
+ break;
+ }
+
+ // Signal Board has reset
+ SendtoTFTLN(AC_msg_main_board_has_reset);
+
+ // Enable leveling and Disable end stops during print
+ // as Z home places nozzle above the bed so we need to allow it past the end stops
+ injectCommands(AC_cmnd_enable_leveling);
+
+ // Startup tunes are defined in Tunes.h
+ PlayTune(BEEPER_PIN, TERN(AC_DEFAULT_STARTUP_TUNE, Anycubic_PowerOn, GB_PowerOn), 1);
+
+ #if ACDEBUGLEVEL
+ SERIAL_ECHOLNPGM("AC Debug Level ", ACDEBUGLEVEL);
+ #endif
+ SendtoTFTLN(AC_msg_ready);
+}
+
+void ChironTFT::DetectPanelType() {
+ #if AUTO_DETECT_CHIRON_TFT
+ // Send a query to the TFT
+ SendtoTFTLN(AC_Test_for_OldPanel); // The panel will respond with 'SXY 480 320'
+ SendtoTFTLN(AC_Test_for_NewPanel); // the panel will respond with '[0]=0 ' to '[19]=0 '
+ #endif
+}
+
+void ChironTFT::IdleLoop() {
+ if (ReadTFTCommand()) {
+ ProcessPanelRequest();
+ command_len = 0;
+ }
+ CheckHeaters();
+}
+
+void ChironTFT::PrinterKilled(FSTR_P const error, FSTR_P const component) {
+ SendtoTFTLN(AC_msg_kill_lcd);
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPGM("PrinterKilled()\nerror: ", error , "\ncomponent: ", component);
+ #endif
+}
+
+void ChironTFT::MediaEvent(media_event_t event) {
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPGM("ProcessMediaStatus() ", event);
+ #endif
+ switch (event) {
+ case AC_media_inserted:
+ SendtoTFTLN(AC_msg_sd_card_inserted);
+ break;
+
+ case AC_media_removed:
+ SendtoTFTLN(AC_msg_sd_card_removed);
+ break;
+
+ case AC_media_error:
+ last_error = AC_error_noSD;
+ SendtoTFTLN(AC_msg_no_sd_card);
+ break;
+ }
+}
+
+void ChironTFT::TimerEvent(timer_event_t event) {
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPGM("TimerEvent() ", event);
+ SERIAL_ECHOLNPGM("Printer State: ", printer_state);
+ #endif
+
+ switch (event) {
+ case AC_timer_started: {
+ live_Zoffset = 0.0; // reset print offset
+ setSoftEndstopState(false); // disable endstops to print
+ printer_state = AC_printer_printing;
+ SendtoTFTLN(AC_msg_print_from_sd_card);
+ } break;
+
+ case AC_timer_paused: {
+ printer_state = AC_printer_paused;
+ pause_state = AC_paused_idle;
+ SendtoTFTLN(AC_msg_paused);
+ } break;
+
+ case AC_timer_stopped: {
+ if (printer_state != AC_printer_idle) {
+ printer_state = AC_printer_stopping;
+ SendtoTFTLN(AC_msg_print_complete);
+ }
+ setSoftEndstopState(true); // enable endstops
+ } break;
+ }
+}
+
+void ChironTFT::FilamentRunout() {
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPGM("FilamentRunout() printer_state ", printer_state);
+ #endif
+ // 1 Signal filament out
+ last_error = AC_error_filament_runout;
+ SendtoTFTLN(isPrintingFromMedia() ? AC_msg_filament_out_alert : AC_msg_filament_out_block);
+ PlayTune(BEEPER_PIN, FilamentOut, 1);
+}
+
+void ChironTFT::ConfirmationRequest(const char * const msg) {
+ // M108 continue
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPGM("ConfirmationRequest() ", msg, " printer_state:", printer_state);
+ #endif
+ switch (printer_state) {
+ case AC_printer_pausing: {
+ if (strcmp_P(msg, MARLIN_msg_print_paused) == 0 || strcmp_P(msg, MARLIN_msg_nozzle_parked) == 0) {
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ printer_state = AC_printer_paused;
+ }
+ } break;
+
+ case AC_printer_resuming_from_power_outage:
+ case AC_printer_printing:
+ case AC_printer_paused: {
+ // Heater timeout, send acknowledgement
+ if (strcmp_P(msg, MARLIN_msg_heater_timeout) == 0) {
+ pause_state = AC_paused_heater_timed_out;
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ PlayTune(BEEPER_PIN,Heater_Timedout,1);
+ }
+ // Reheat finished, send acknowledgement
+ else if (strcmp_P(msg, MARLIN_msg_reheat_done) == 0) {
+ pause_state = AC_paused_idle;
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ }
+ // Filament Purging, send acknowledgement enter run mode
+ else if (strcmp_P(msg, MARLIN_msg_filament_purging) == 0) {
+ pause_state = AC_paused_purging_filament;
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ }
+ } break;
+ default:
+ break;
+ }
+}
+
+void ChironTFT::StatusChange(const char * const msg) {
+ #if ACDEBUG(AC_MARLIN)
+ SERIAL_ECHOLNPGM("StatusChange() ", msg);
+ SERIAL_ECHOLNPGM("printer_state:", printer_state);
+ #endif
+ bool msg_matched = false;
+ // The only way to get printer status is to parse messages
+ // Use the state to minimise the work we do here.
+ switch (printer_state) {
+ case AC_printer_probing: {
+ // If probing completes ok save the mesh and park
+ // Ignore the custom machine name
+ if (strcmp_P(msg + strlen(MACHINE_NAME), MARLIN_msg_ready) == 0) {
+ injectCommands(F("M500\nG27"));
+ SendtoTFTLN(AC_msg_probing_complete);
+ printer_state = AC_printer_idle;
+ msg_matched = true;
+ }
+ // If probing fails don't save the mesh raise the probe above the bad point
+ if (strcmp_P(msg, MARLIN_msg_probing_failed) == 0) {
+ PlayTune(BEEPER_PIN, BeepBeepBeeep, 1);
+ injectCommands(F("G1 Z50 F500"));
+ SendtoTFTLN(AC_msg_probing_complete);
+ printer_state = AC_printer_idle;
+ msg_matched = true;
+ }
+ } break;
+
+ case AC_printer_printing: {
+ if (strcmp_P(msg, MARLIN_msg_reheating) == 0) {
+ SendtoTFTLN(AC_msg_paused); // enable continue button
+ msg_matched = true;
+ }
+ } break;
+
+ case AC_printer_pausing: {
+ if (strcmp_P(msg, MARLIN_msg_print_paused) == 0) {
+ SendtoTFTLN(AC_msg_paused);
+ printer_state = AC_printer_paused;
+ pause_state = AC_paused_idle;
+ msg_matched = true;
+ }
+ } break;
+
+ case AC_printer_stopping: {
+ if (strcmp_P(msg, MARLIN_msg_print_aborted) == 0) {
+ SendtoTFTLN(AC_msg_stop);
+ printer_state = AC_printer_idle;
+ msg_matched = true;
+ }
+ } break;
+ default:
+ break;
+ }
+
+ // If not matched earlier see if this was a heater message
+ if (!msg_matched) {
+ if (strcmp_P(msg, MARLIN_msg_extruder_heating) == 0) {
+ SendtoTFTLN(AC_msg_nozzle_heating);
+ hotend_state = AC_heater_temp_set;
+ }
+ else if (strcmp_P(msg, MARLIN_msg_bed_heating) == 0) {
+ SendtoTFTLN(AC_msg_bed_heating);
+ hotbed_state = AC_heater_temp_set;
+ }
+ else if (strcmp_P(msg, MARLIN_msg_EEPROM_version) == 0) {
+ last_error = AC_error_EEPROM;
+ }
+ }
+}
+
+void ChironTFT::PowerLossRecovery() {
+ printer_state = AC_printer_resuming_from_power_outage; // Play tune to notify user we can recover.
+ last_error = AC_error_powerloss;
+ PlayTune(BEEPER_PIN, SOS, 1);
+ SERIAL_ECHOLNF(AC_msg_powerloss_recovery);
+}
+
+void ChironTFT::PrintComplete() {
+ SendtoTFT(AC_msg_print_complete);
+ printer_state = AC_printer_idle;
+ setSoftEndstopState(true); // enable endstops
+}
+
+void ChironTFT::SendtoTFT(FSTR_P const fstr/*=nullptr*/) { // A helper to print PROGMEM string to the panel
+ #if ACDEBUG(AC_SOME)
+ SERIAL_ECHOF(fstr);
+ #endif
+ PGM_P str = FTOP(fstr);
+ while (const char c = pgm_read_byte(str++)) TFTSer.write(c);
+}
+
+void ChironTFT::SendtoTFTLN(FSTR_P const fstr/*=nullptr*/) {
+ if (fstr) {
+ #if ACDEBUG(AC_SOME)
+ SERIAL_ECHOPGM("> ");
+ #endif
+ SendtoTFT(fstr);
+ #if ACDEBUG(AC_SOME)
+ SERIAL_EOL();
+ #endif
+ }
+ TFTSer.println();
+}
+
+bool ChironTFT::ReadTFTCommand() {
+ bool command_ready = false;
+ while (TFTSer.available() > 0 && command_len < MAX_CMND_LEN) {
+ panel_command[command_len] = TFTSer.read();
+ if (panel_command[command_len] == '\n') {
+ command_ready = true;
+ break;
+ }
+ command_len++;
+ }
+
+ if (command_ready || command_len == MAX_CMND_LEN) {
+ panel_command[command_len] = '\0';
+ #if ACDEBUG(AC_ALL)
+ SERIAL_ECHOLNPGM("len(",command_len,") < ", panel_command);
+ #endif
+ command_ready = true;
+ }
+ return command_ready;
+}
+
+int8_t ChironTFT::FindToken(char c) {
+ for (int8_t pos = 0; pos < command_len; pos++) {
+ if (panel_command[pos] == c) {
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Tpos:", pos, " ", c);
+ #endif
+ return pos;
+ }
+ }
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Not found: ", c);
+ #endif
+ return -1;
+}
+
+void ChironTFT::CheckHeaters() {
+ uint8_t faultDuration = 0;
+
+ // if the hotend temp is abnormal, confirm state before signalling panel
+ celsius_float_t temp = getActualTemp_celsius(E0);
+ while (!WITHIN(temp, HEATER_0_MINTEMP, HEATER_0_MAXTEMP)) {
+ faultDuration++;
+ if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) {
+ SendtoTFTLN(AC_msg_nozzle_temp_abnormal);
+ last_error = AC_error_abnormal_temp_t0;
+ SERIAL_ECHOLNPGM("Extruder temp abnormal! : ", temp);
+ break;
+ }
+ delay_ms(500);
+ temp = getActualTemp_celsius(E0);
+ }
+
+ // If the hotbed temp is abnormal, confirm state before signaling panel
+ faultDuration = 0;
+ temp = getActualTemp_celsius(BED);
+ while (!WITHIN(temp, BED_MINTEMP, BED_MAXTEMP)) {
+ faultDuration++;
+ if (faultDuration >= AC_HEATER_FAULT_VALIDATION_TIME) {
+ SendtoTFTLN(AC_msg_nozzle_temp_abnormal);
+ last_error = AC_error_abnormal_temp_bed;
+ SERIAL_ECHOLNPGM("Bed temp abnormal! : ", temp);
+ break;
+ }
+ delay_ms(500);
+ temp = getActualTemp_celsius(E0);
+ }
+
+ // Update panel with hotend heater status
+ if (hotend_state != AC_heater_temp_reached) {
+ if (WITHIN(getActualTemp_celsius(E0) - getTargetTemp_celsius(E0), -(TEMP_WINDOW), TEMP_WINDOW)) {
+ SendtoTFTLN(AC_msg_nozzle_heating_done);
+ hotend_state = AC_heater_temp_reached;
+ }
+ }
+
+ // Update panel with bed heater status
+ if (hotbed_state != AC_heater_temp_reached) {
+ if (WITHIN(getActualTemp_celsius(BED) - getTargetTemp_celsius(BED), -(TEMP_BED_WINDOW), TEMP_BED_WINDOW)) {
+ SendtoTFTLN(AC_msg_bed_heating_done);
+ hotbed_state = AC_heater_temp_reached;
+ }
+ }
+}
+
+void ChironTFT::SendFileList(int8_t startindex) {
+ // Respond to panel request for 4 files starting at index
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("## SendFileList ## ", startindex);
+ #endif
+ SendtoTFTLN(F("FN "));
+ filenavigator.getFiles(startindex, panel_type, 4);
+ SendtoTFTLN(F("END"));
+}
+
+void ChironTFT::SelectFile() {
+ if (panel_type <= AC_panel_new) {
+ strncpy(selectedfile, panel_command + 4, command_len - 3);
+ selectedfile[command_len - 4] = '\0';
+ }
+ else {
+ strncpy(selectedfile, panel_command + 4, command_len - 4);
+ selectedfile[command_len - 5] = '\0';
+ }
+ #if ACDEBUG(AC_FILE)
+ SERIAL_ECHOLNPGM(" Selected File: ",selectedfile);
+ #endif
+ switch (selectedfile[0]) {
+ case '/': // Valid file selected
+ SendtoTFTLN(AC_msg_sd_file_open_success);
+ break;
+
+ case '<': // .. (go up folder level)
+ filenavigator.upDIR();
+ SendtoTFTLN(AC_msg_sd_file_open_failed);
+ SendFileList( 0 );
+ break;
+ default: // enter sub folder
+ // for new panel remove the '.GCO' tag that was added to the end of the path
+ if (panel_type <= AC_panel_new)
+ selectedfile[strlen(selectedfile) - 4] = '\0';
+ filenavigator.changeDIR(selectedfile);
+ SendtoTFTLN(AC_msg_sd_file_open_failed);
+ SendFileList( 0 );
+ break;
+ }
+}
+
+void ChironTFT::ProcessPanelRequest() {
+ // Break these up into logical blocks // as its easier to navigate than one huge switch case!
+ int8_t tpos = FindToken('A');
+ // Panel request are 'A0' - 'A36'
+ if (tpos >= 0) {
+ const int8_t req = atoi(&panel_command[tpos + 1]);
+
+ // Information requests A0 - A8 and A33
+ if (req <= 8 || req == 33) PanelInfo(req);
+
+ // Simple Actions A9 - A28
+ else if (req <= 28) PanelAction(req);
+
+ // Process Initiation
+ else if (req <= 36) PanelProcess(req);
+ }
+ else {
+ #if AUTO_DETECT_CHIRON_TFT
+ // This may be a response to a panel type detection query
+ if (panel_type == AC_panel_unknown) {
+ tpos = FindToken('S'); // old panel will respond to 'SIZE' with 'SXY 480 320'
+ if (tpos >= 0) {
+ if (panel_command[tpos + 1] == 'X' && panel_command[tpos + 2] =='Y') {
+ panel_type = AC_panel_standard;
+ SERIAL_ECHOLNF(AC_msg_old_panel_detected);
+ }
+ }
+ else {
+ // new panel will respond to 'J200' with '[0]=0'
+ // it seems only after a power cycle so detection assumes a new panel
+ tpos = FindToken('[');
+ if (tpos >= 0) {
+ if (panel_command[tpos + 1] == '0' && panel_command[tpos + 2] ==']') {
+ panel_type = AC_panel_new;
+ SERIAL_ECHOLNF(AC_msg_new_panel_detected);
+ }
+ }
+ }
+ return;
+ }
+ #endif
+
+ SendtoTFTLN(); // Ignore unknown requests
+ }
+}
+
+void ChironTFT::PanelInfo(uint8_t req) {
+ // information requests A0-A8 and A33
+ switch (req) {
+ case 0: // A0 Get HOTEND Temp
+ SendtoTFT(F("A0V "));
+ TFTSer.println(getActualTemp_celsius(E0));
+ break;
+
+ case 1: // A1 Get HOTEND Target Temp
+ SendtoTFT(F("A1V "));
+ TFTSer.println(getTargetTemp_celsius(E0));
+ break;
+
+ case 2: // A2 Get BED Temp
+ SendtoTFT(F("A2V "));
+ TFTSer.println(getActualTemp_celsius(BED));
+ break;
+
+ case 3: // A3 Get BED Target Temp
+ SendtoTFT(F("A3V "));
+ TFTSer.println(getTargetTemp_celsius(BED));
+ break;
+
+ case 4: // A4 Get FAN Speed
+ SendtoTFT(F("A4V "));
+ TFTSer.println(getActualFan_percent(FAN0));
+ break;
+
+ case 5: // A5 Get Current Coordinates
+ SendtoTFT(F("A5V X: "));
+ TFTSer.print(getAxisPosition_mm(X));
+ SendtoTFT(F(" Y: "));
+ TFTSer.print(getAxisPosition_mm(Y));
+ SendtoTFT(F(" Z: "));
+ TFTSer.println(getAxisPosition_mm(Z));
+ break;
+
+ case 6: // A6 Get printing progress
+ if (isPrintingFromMedia()) {
+ SendtoTFT(F("A6V "));
+ TFTSer.println(ui8tostr2(getProgress_percent()));
+ }
+ else
+ SendtoTFTLN(F("A6V ---"));
+ break;
+
+ case 7: { // A7 Get Printing Time
+ uint32_t time = getProgress_seconds_elapsed() / 60;
+ SendtoTFT(F("A7V "));
+ TFTSer.print(ui8tostr2(time / 60));
+ SendtoTFT(F(" H "));
+ TFTSer.print(ui8tostr2(time % 60));
+ SendtoTFT(F(" M"));
+ #if ACDEBUG(AC_ALL)
+ SERIAL_ECHOLNPGM("Print time ", ui8tostr2(time / 60), ":", ui8tostr2(time % 60));
+ #endif
+ } break;
+
+ case 8: // A8 Get SD Card list A8 S0
+ if (!isMediaInserted()) safe_delay(500);
+ if (!isMediaInserted()) // Make sure the card is removed
+ SendtoTFTLN(AC_msg_no_sd_card);
+ else if (panel_command[3] == 'S')
+ SendFileList( atoi( &panel_command[4] ) );
+ break;
+
+ case 33: // A33 Get firmware info
+ SendtoTFT(F("J33 "));
+ // If there is an error recorded, show that instead of the FW version
+ if (!GetLastError()) SendtoTFTLN(F(SHORT_BUILD_VERSION));
+ break;
+ }
+}
+
+void ChironTFT::PanelAction(uint8_t req) {
+ switch (req) {
+ case 9: // A9 Pause SD print
+ if (isPrintingFromMedia()) {
+ SendtoTFTLN(AC_msg_pause);
+ pausePrint();
+ printer_state = AC_printer_pausing;
+ }
+ else
+ SendtoTFTLN(AC_msg_stop);
+ break;
+
+ case 10: // A10 Resume SD Print
+ if (pause_state == AC_paused_idle || printer_state == AC_printer_resuming_from_power_outage)
+ resumePrint();
+ else
+ setUserConfirmed();
+ break;
+
+ case 11: // A11 Stop SD print
+ if (isPrintingFromMedia()) {
+ printer_state = AC_printer_stopping;
+ stopPrint();
+ }
+ else {
+ if (printer_state == AC_printer_resuming_from_power_outage)
+ injectCommands(F("M1000 C")); // Cancel recovery
+ SendtoTFTLN(AC_msg_stop);
+ printer_state = AC_printer_idle;
+ }
+ break;
+
+ case 12: // A12 Kill printer
+ kill(); // from marlincore.h
+ break;
+
+ case 13: // A13 Select file
+ SelectFile();
+ break;
+
+ case 14: // A14 Start Printing
+ // Allows printer to restart the job if we don't want to recover
+ if (printer_state == AC_printer_resuming_from_power_outage) {
+ injectCommands(F("M1000 C")); // Cancel recovery
+ printer_state = AC_printer_idle;
+ }
+ #if ACDebugLevel >= 1
+ SERIAL_ECHOLNPGM("Print: ", selectedfile);
+ #endif
+ printFile(selectedfile);
+ SendtoTFTLN(AC_msg_print_from_sd_card);
+ break;
+
+ case 15: // A15 Resuming from outage
+ if (printer_state == AC_printer_resuming_from_power_outage) {
+ // Need to home here to restore the Z position
+ injectCommands(AC_cmnd_power_loss_recovery);
+ injectCommands(F("M1000")); // home and start recovery
+ }
+ break;
+
+ case 16: { // A16 Set HotEnd temp A17 S170
+ const float set_Htemp = atof(&panel_command[5]);
+ hotend_state = set_Htemp ? AC_heater_temp_set : AC_heater_off;
+ switch ((char)panel_command[4]) {
+ // Set Temp
+ case 'S': case 'C': setTargetTemp_celsius(set_Htemp, E0);
+ }
+ } break;
+
+ case 17: { // A17 Set bed temp
+ const float set_Btemp = atof(&panel_command[5]);
+ hotbed_state = set_Btemp ? AC_heater_temp_set : AC_heater_off;
+ if (panel_command[4] == 'S')
+ setTargetTemp_celsius(set_Btemp, BED);
+ } break;
+
+ case 18: // A18 Set Fan Speed
+ if (panel_command[4] == 'S')
+ setTargetFan_percent(atof(&panel_command[5]), FAN0);
+ break;
+
+ case 19: // A19 Motors off
+ if (!isPrinting()) {
+ stepper.disable_all_steppers();
+ SendtoTFTLN(AC_msg_ready);
+ }
+ break;
+
+ case 20: // A20 Read/write print speed
+ if (panel_command[4] == 'S')
+ setFeedrate_percent(atoi(&panel_command[5]));
+ else {
+ SendtoTFT(F("A20V "));
+ TFTSer.println(getFeedrate_percent());
+ }
+ break;
+
+ case 21: // A21 Home Axis A21 X
+ if (!isPrinting()) {
+ switch ((char)panel_command[4]) {
+ case 'X': injectCommands(F("G28X")); break;
+ case 'Y': injectCommands(F("G28Y")); break;
+ case 'Z': injectCommands(F("G28Z")); break;
+ case 'C': injectCommands_P(G28_STR); break;
+ }
+ }
+ break;
+
+ case 22: { // A22 Move Axis
+ // The commands have changed on the new panel
+ // Old TFT A22 X -1F1500 A22 X +1F1500
+ // New TFT A22 X-1.0 F1500 A22 X1.0 F1500
+
+ // Send a G-code-relative non-print move and let the controller deal with it
+ // G91 G0 G90
+
+ if (!isPrinting()) { // Ignore request if printing
+ char MoveCmnd[30];
+ sprintf_P(MoveCmnd, PSTR("G91\nG0%s\nG90"), panel_command + 3);
+ #if ACDEBUG(AC_ACTION)
+ SERIAL_ECHOLNPGM("Move: ", MoveCmnd);
+ #endif
+ setSoftEndstopState(true); // enable endstops
+ injectCommands(MoveCmnd);
+ }
+ } break;
+
+ case 23: // A23 Preheat PLA
+ // Ignore request if printing
+ if (!isPrinting()) {
+ // Temps defined in configuration.h
+ setTargetTemp_celsius(PREHEAT_1_TEMP_BED, BED);
+ setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, E0);
+ SendtoTFTLN();
+ hotbed_state = AC_heater_temp_set;
+ hotend_state = AC_heater_temp_set;
+ }
+ break;
+
+ case 24: // A24 Preheat ABS
+ // Ignore request if printing
+ if (!isPrinting()) {
+ setTargetTemp_celsius(PREHEAT_2_TEMP_BED, BED);
+ setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, E0);
+ SendtoTFTLN();
+ hotbed_state = AC_heater_temp_set;
+ hotend_state = AC_heater_temp_set;
+ }
+ break;
+
+ case 25: // A25 Cool Down
+ // Ignore request if printing
+ if (!isPrinting()) {
+ setTargetTemp_celsius(0, E0);
+ setTargetTemp_celsius(0, BED);
+ SendtoTFTLN(AC_msg_ready);
+ hotbed_state = AC_heater_off;
+ hotend_state = AC_heater_off;
+ }
+ break;
+
+ case 26: // A26 Refresh SD
+ if (card.isMounted())card.release();
+ card.mount();
+ safe_delay(500);
+ filenavigator.reset();
+ break;
+
+ case 27: // A27 Servo Angles adjust
+ break;
+
+ case 28: // A28 Filament set A28 O/C
+ // Ignore request if printing
+ if (isPrinting()) break;
+ SendtoTFTLN();
+ break;
+ }
+}
+
+void ChironTFT::PanelProcess(uint8_t req) {
+ switch (req) {
+ case 29: { // A29 Read Mesh Point A29 X1 Y1
+ xy_uint8_t pos;
+ float pos_z;
+ pos.x = atoi(&panel_command[FindToken('X')+1]);
+ pos.y = atoi(&panel_command[FindToken('Y')+1]);
+ pos_z = getMeshPoint(pos);
+
+ SendtoTFT(F("A29V "));
+ TFTSer.println(pos_z * 100);
+ if (!isPrinting()) {
+ setSoftEndstopState(true); // disable endstops
+ // If the same meshpoint is selected twice in a row, move the head to that ready for adjustment
+ if ((selectedmeshpoint.x == pos.x) && (selectedmeshpoint.y == pos.y)) {
+ if (!isPositionKnown())
+ injectCommands_P(G28_STR); // home
+
+ if (isPositionKnown()) {
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Moving to mesh point at x: ", pos.x, " y: ", pos.y, " z: ", pos_z);
+ #endif
+ // Go up before moving
+ setAxisPosition_mm(3.0,Z);
+
+ setAxisPosition_mm(17 + (93 * pos.x), X);
+ setAxisPosition_mm(20 + (93 * pos.y), Y);
+ setAxisPosition_mm(0.0, Z);
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Current Z: ", getAxisPosition_mm(Z));
+ #endif
+ }
+ }
+ selectedmeshpoint.x = pos.x;
+ selectedmeshpoint.y = pos.y;
+ }
+ } break;
+
+ case 30: // A30 Auto leveling
+ if (FindToken('S') >= 0) { // Start probing New panel adds spaces..
+ // Ignore request if printing
+ if (isPrinting())
+ SendtoTFTLN(AC_msg_probing_not_allowed); // forbid auto leveling
+ else {
+ SendtoTFTLN(AC_msg_start_probing);
+ injectCommands(F("G28\nG29"));
+ printer_state = AC_printer_probing;
+ }
+ }
+ else
+ SendtoTFTLN(AC_msg_start_probing); // Just enter levelling menu
+ break;
+
+ case 31: // A31 Adjust all Probe Points
+ // The tokens can occur in different places on the new panel so we need to find it.
+
+ if (FindToken('C') >= 0) { // Restore and apply original offsets
+ if (!isPrinting()) {
+ injectCommands(F("M501\nM420 S1"));
+ selectedmeshpoint.x = selectedmeshpoint.y = 99;
+ SERIAL_ECHOLNF(AC_msg_mesh_changes_abandoned);
+ }
+ }
+
+ else if (FindToken('D') >= 0) { // Save Z Offset tables and restore leveling state
+ if (!isPrinting()) {
+ setAxisPosition_mm(1.0,Z); // Lift nozzle before any further movements are made
+ injectCommands(F("M500"));
+ SERIAL_ECHOLNF(AC_msg_mesh_changes_saved);
+ selectedmeshpoint.x = selectedmeshpoint.y = 99;
+ }
+ }
+
+ else if (FindToken('G') >= 0) { // Get current offset
+ SendtoTFT(F("A31V "));
+ // When printing use the live z Offset position
+ // we will use babystepping to move the print head
+ if (isPrinting())
+ TFTSer.println(live_Zoffset);
+ else {
+ TFTSer.println(getZOffset_mm());
+ selectedmeshpoint.x = selectedmeshpoint.y = 99;
+ }
+ }
+
+ else {
+ int8_t tokenpos = FindToken('S');
+ if (tokenpos >= 0) { // Set offset (adjusts all points by value)
+ float Zshift = atof(&panel_command[tokenpos+1]);
+ setSoftEndstopState(false); // disable endstops
+ // Allow temporary Z position nudging during print
+ // From the leveling panel use the all points UI to adjust the print pos.
+ if (isPrinting()) {
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Change Zoffset from:", live_Zoffset, " to ", live_Zoffset + Zshift);
+ #endif
+ if (isAxisPositionKnown(Z)) {
+ #if ACDEBUG(AC_INFO)
+ const float currZpos = getAxisPosition_mm(Z);
+ SERIAL_ECHOLNPGM("Nudge Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05));
+ #endif
+ // Use babystepping to adjust the head position
+ int16_t steps = mmToWholeSteps(constrain(Zshift,-0.05,0.05), Z);
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Steps to move Z: ", steps);
+ #endif
+ babystepAxis_steps(steps, Z);
+ live_Zoffset += Zshift;
+ }
+ SendtoTFT(F("A31V "));
+ TFTSer.println(live_Zoffset);
+ }
+ else {
+ GRID_LOOP(x, y) {
+ const xy_uint8_t pos { x, y };
+ const float currval = getMeshPoint(pos);
+ setMeshPoint(pos, constrain(currval + Zshift, AC_LOWEST_MESHPOINT_VAL, 2));
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Change mesh point X", x," Y",y ," from ", currval, " to ", getMeshPoint(pos) );
+ #endif
+ }
+ const float currZOffset = getZOffset_mm();
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Change probe offset from ", currZOffset, " to ", currZOffset + Zshift);
+ #endif
+
+ setZOffset_mm(currZOffset + Zshift);
+ SendtoTFT(F("A31V "));
+ TFTSer.println(getZOffset_mm());
+
+ if (isAxisPositionKnown(Z)) {
+ // Move Z axis
+ const float currZpos = getAxisPosition_mm(Z);
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Move Z pos from ", currZpos, " to ", currZpos + constrain(Zshift, -0.05, 0.05));
+ #endif
+ setAxisPosition_mm(currZpos+constrain(Zshift,-0.05,0.05),Z);
+ }
+ }
+ }
+ }
+ break;
+
+ case 32: // A32 clean leveling beep flag
+ // Ignore request if printing
+ //if (isPrinting()) break;
+ //injectCommands(F("M500\nM420 S1\nG1 Z10 F240\nG1 X0 Y0 F6000"));
+ //TFTSer.println();
+ break;
+
+ // A33 firmware info request see PanelInfo()
+
+ case 34: // A34 Adjust single mesh point A34 C/S X1 Y1 V123
+ if (panel_command[3] == 'C') { // Restore original offsets
+ injectCommands(F("M501\nM420 S1"));
+ selectedmeshpoint.x = selectedmeshpoint.y = 99;
+ //printer_state = AC_printer_idle;
+ }
+ else {
+ xy_uint8_t pos;
+ pos.x = atoi(&panel_command[5]);
+ pos.y = atoi(&panel_command[8]);
+
+ float currmesh = getMeshPoint(pos);
+ float newval = atof(&panel_command[11])/100;
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Change mesh point x:", pos.x, " y:", pos.y);
+ SERIAL_ECHOLNPGM("from ", currmesh, " to ", newval);
+ #endif
+ // Update Meshpoint
+ setMeshPoint(pos,newval);
+ if (printer_state == AC_printer_idle || printer_state == AC_printer_probing /*!isPrinting()*/) {
+ // if we are at the current mesh point indicated on the panel Move Z pos +/- 0.05mm
+ // (The panel changes the mesh value by +/- 0.05mm on each button press)
+ if (selectedmeshpoint.x == pos.x && selectedmeshpoint.y == pos.y) {
+ setSoftEndstopState(false);
+ float currZpos = getAxisPosition_mm(Z);
+ #if ACDEBUG(AC_INFO)
+ SERIAL_ECHOLNPGM("Move Z pos from ", currZpos, " to ", currZpos + constrain(newval - currmesh, -0.05, 0.05));
+ #endif
+ setAxisPosition_mm(currZpos + constrain(newval - currmesh, -0.05, 0.05), Z);
+ }
+ }
+ }
+ break;
+
+ case 36: // A36 Auto leveling for new TFT bet that was a typo in the panel code!
+ SendtoTFTLN(AC_msg_start_probing);
+ break;
+ }
+}
+
+bool ChironTFT::GetLastError() {
+ switch (last_error) {
+ case AC_error_abnormal_temp_bed: SendtoTFTLN(AC_msg_error_bed_temp); break;
+ case AC_error_abnormal_temp_t0: SendtoTFTLN(AC_msg_error_hotend_temp); break;
+ case AC_error_noSD: SendtoTFTLN(AC_msg_error_sd_card); break;
+ case AC_error_powerloss: SendtoTFTLN(AC_msg_power_loss); break;
+ case AC_error_EEPROM: SendtoTFTLN(AC_msg_eeprom_version); break;
+ case AC_error_filament_runout: SendtoTFTLN(AC_msg_filament_out); break;
+ default: return false;
+ }
+ last_error = AC_error_none;
+ return true;
+}
+
+} // Anycubic namespace
+
+#endif // ANYCUBIC_LCD_CHIRON
diff --git a/src/lcd/extui/anycubic_chiron/chiron_tft.h b/src/lcd/extui/anycubic_chiron/chiron_tft.h
new file mode 100644
index 0000000..c9a32e5
--- /dev/null
+++ b/src/lcd/extui/anycubic_chiron/chiron_tft.h
@@ -0,0 +1,89 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/anycubic_chiron/chiron_tft.h
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+#include "chiron_tft_defs.h"
+#include "../../../inc/MarlinConfigPre.h"
+#include "../ui_api.h"
+
+#if NONE(CHIRON_TFT_STANDARD, CHIRON_TFT_NEW)
+ #define AUTO_DETECT_CHIRON_TFT 1
+#endif
+
+namespace Anycubic {
+
+class ChironTFT {
+ #if AUTO_DETECT_CHIRON_TFT
+ static panel_type_t panel_type;
+ #else
+ static constexpr panel_type_t panel_type = TERN(CHIRON_TFT_NEW, AC_panel_new, AC_panel_standard);
+ #endif
+ static last_error_t last_error;
+ static printer_state_t printer_state;
+ static paused_state_t pause_state;
+ static heater_state_t hotend_state;
+ static heater_state_t hotbed_state;
+ static xy_uint8_t selectedmeshpoint;
+ static char panel_command[MAX_CMND_LEN + 1];
+ static uint8_t command_len;
+ static char selectedfile[MAX_PATH_LEN + 1];
+ static float live_Zoffset;
+ static file_menu_t file_menu;
+ public:
+ static void Startup();
+ static void IdleLoop();
+ static void PrinterKilled(FSTR_P, FSTR_P);
+ static void MediaEvent(media_event_t);
+ static void TimerEvent(timer_event_t);
+ static void FilamentRunout();
+ static void ConfirmationRequest(const char * const);
+ static void StatusChange(const char * const);
+ static void PowerLossRecovery();
+ static void PrintComplete();
+ static void SendtoTFT(FSTR_P const=nullptr);
+ static void SendtoTFTLN(FSTR_P const=nullptr);
+ private:
+ static void DetectPanelType();
+ static bool ReadTFTCommand();
+ static int8_t FindToken(char);
+ static void CheckHeaters();
+ static void SendFileList(int8_t);
+ static void SelectFile();
+ static void InjectCommandandWait(PGM_P);
+ static void ProcessPanelRequest();
+ static void PanelInfo(uint8_t);
+ static void PanelAction(uint8_t);
+ static void PanelProcess(uint8_t);
+ static bool GetLastError();
+};
+
+extern ChironTFT Chiron;
+
+} // Anycubic namespace
diff --git a/src/lcd/extui/anycubic_chiron/chiron_tft_defs.h b/src/lcd/extui/anycubic_chiron/chiron_tft_defs.h
new file mode 100644
index 0000000..e3609b5
--- /dev/null
+++ b/src/lcd/extui/anycubic_chiron/chiron_tft_defs.h
@@ -0,0 +1,182 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/anycubic_chiron/chiron_defs.h
+ *
+ * Extensible_UI implementation for Anycubic Chiron
+ * Written By Nick Wells, 2020 [https://github.com/SwiftNick]
+ * (not affiliated with Anycubic, Ltd.)
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+//#define ACDEBUGLEVEL 4
+
+#if ACDEBUGLEVEL
+ // Bit-masks for selective debug:
+ enum ACDebugMask : uint8_t {
+ AC_INFO = 1,
+ AC_ACTION = 2,
+ AC_FILE = 4,
+ AC_PANEL = 8,
+ AC_MARLIN = 16,
+ AC_SOME = 32,
+ AC_ALL = 64
+ };
+ #define ACDEBUG(mask) ( ((mask) & ACDEBUGLEVEL) == mask ) // Debug flag macro
+#else
+ #define ACDEBUG(mask) false
+#endif
+
+#define TFTSer LCD_SERIAL // Serial interface for TFT panel now uses marlinserial
+#define MAX_FOLDER_DEPTH 4 // Limit folder depth TFT has a limit for the file path
+#define MAX_CMND_LEN 16 * MAX_FOLDER_DEPTH // Maximum Length for a Panel command
+#define MAX_PATH_LEN 16 * MAX_FOLDER_DEPTH // Maximum number of characters in a SD file path
+
+#define AC_HEATER_FAULT_VALIDATION_TIME 5 // number of 1/2 second loops before signalling a heater fault
+#define AC_LOWEST_MESHPOINT_VAL -10 // The lowest value you can set for a single mesh point offset
+
+ // TFT panel commands
+#define AC_msg_sd_card_inserted F("J00")
+#define AC_msg_sd_card_removed F("J01")
+#define AC_msg_no_sd_card F("J02")
+#define AC_msg_usb_connected F("J03")
+#define AC_msg_print_from_sd_card F("J04")
+#define AC_msg_pause F("J05")
+#define AC_msg_nozzle_heating F("J06")
+#define AC_msg_nozzle_heating_done F("J07")
+#define AC_msg_bed_heating F("J08")
+#define AC_msg_bed_heating_done F("J09")
+#define AC_msg_nozzle_temp_abnormal F("J10")
+#define AC_msg_kill_lcd F("J11")
+#define AC_msg_ready F("J12")
+#define AC_msg_low_nozzle_temp F("J13")
+#define AC_msg_print_complete F("J14")
+#define AC_msg_filament_out_alert F("J15")
+#define AC_msg_stop F("J16")
+#define AC_msg_main_board_has_reset F("J17")
+#define AC_msg_paused F("J18")
+#define AC_msg_j19_unknown F("J19")
+#define AC_msg_sd_file_open_success F("J20")
+#define AC_msg_sd_file_open_failed F("J21")
+#define AC_msg_level_monitor_finished F("J22")
+#define AC_msg_filament_out_block F("J23")
+#define AC_msg_probing_not_allowed F("J24")
+#define AC_msg_probing_complete F("J25")
+#define AC_msg_start_probing F("J26")
+#define AC_msg_version F("J27")
+#define AC_msg_mesh_changes_abandoned F("Mesh changes abandoned, previous mesh restored.")
+#define AC_msg_mesh_changes_saved F("Mesh changes saved.")
+#define AC_msg_old_panel_detected F("Standard TFT panel detected!")
+#define AC_msg_new_panel_detected F("New TFT panel detected!")
+#define AC_msg_auto_panel_detection F("Auto detect panel type (assuming new panel)")
+#define AC_msg_old_panel_set F("Set for standard TFT panel.")
+#define AC_msg_new_panel_set F("Set for new TFT panel.")
+
+#define AC_msg_powerloss_recovery F("Resuming from power outage! select the same SD file then press resume")
+// Error messages must not contain spaces
+#define AC_msg_error_bed_temp F("Abnormal_bed_temp")
+#define AC_msg_error_hotend_temp F("Abnormal_hotend_temp")
+#define AC_msg_error_sd_card F("SD_card_error")
+#define AC_msg_filament_out F("Filament_runout")
+#define AC_msg_power_loss F("Power_failure")
+#define AC_msg_eeprom_version F("EEPROM_ver_wrong")
+
+#define MARLIN_msg_start_probing PSTR("Probing Point 1/25")
+#define MARLIN_msg_probing_failed PSTR("Probing Failed")
+#define MARLIN_msg_ready PSTR(" Ready.")
+#define MARLIN_msg_print_paused PSTR("Print Paused")
+#define MARLIN_msg_print_aborted PSTR("Print Aborted")
+#define MARLIN_msg_extruder_heating PSTR("E Heating...")
+#define MARLIN_msg_bed_heating PSTR("Bed Heating...")
+#define MARLIN_msg_EEPROM_version PSTR("EEPROM Version Error")
+#define MARLIN_msg_nozzle_parked PSTR("Nozzle Parked")
+#define MARLIN_msg_heater_timeout PSTR("Heater Timeout")
+#define MARLIN_msg_reheating PSTR("Reheating...")
+#define MARLIN_msg_reheat_done PSTR("Reheat finished.")
+#define MARLIN_msg_filament_purging PSTR("Filament Purging...")
+#define MARLIN_msg_special_pause PSTR("PB")
+
+#define AC_cmnd_auto_unload_filament F("M701") // Use Marlin unload routine
+#define AC_cmnd_auto_load_filament F("M702 M0 PB") // Use Marlin load routing then pause for user to clean nozzle
+
+#define AC_cmnd_manual_load_filament F("M83\nG1 E50 F700\nM82") // replace the manual panel commands with something a little faster
+#define AC_cmnd_manual_unload_filament F("M83\nG1 E-50 F1200\nM82")
+#define AC_cmnd_enable_leveling F("M420SV")
+#define AC_cmnd_power_loss_recovery F("G28XYR5\nG28Z") // Lift, home X and Y then home Z when in 'safe' position
+
+#define AC_Test_for_OldPanel F("SIZE") // An old panel will respond with 'SXY 480 320' a new panel wont respond.
+#define AC_Test_for_NewPanel F("J200") // A new panel will respond with '[0]=0 [1]=0' to '[19]=0 ' an old panel wont respond
+
+namespace Anycubic {
+ enum heater_state_t : uint8_t {
+ AC_heater_off,
+ AC_heater_temp_set,
+ AC_heater_temp_reached
+ };
+ enum paused_state_t : uint8_t {
+ AC_paused_heater_timed_out,
+ AC_paused_purging_filament,
+ AC_paused_idle
+ };
+ enum printer_state_t : uint8_t {
+ AC_printer_booting,
+ AC_printer_idle,
+ AC_printer_probing,
+ AC_printer_printing,
+ AC_printer_pausing,
+ AC_printer_paused,
+ AC_printer_stopping,
+ AC_printer_resuming_from_power_outage
+ };
+ enum timer_event_t : uint8_t {
+ AC_timer_started,
+ AC_timer_paused,
+ AC_timer_stopped
+ };
+ enum media_event_t : uint8_t {
+ AC_media_inserted,
+ AC_media_removed,
+ AC_media_error
+ };
+ enum file_menu_t : uint8_t {
+ AC_menu_file,
+ AC_menu_command,
+ AC_menu_change_to_file,
+ AC_menu_change_to_command
+ };
+ enum panel_type_t : uint8_t { // order is important here as we assume new panel if type is unknown
+ AC_panel_unknown,
+ AC_panel_new,
+ AC_panel_standard
+ };
+ enum last_error_t : uint8_t {
+ AC_error_none,
+ AC_error_abnormal_temp_t0,
+ AC_error_abnormal_temp_bed,
+ AC_error_noSD,
+ AC_error_powerloss,
+ AC_error_filament_runout,
+ AC_error_EEPROM
+ };
+} // Anycubic namespace
diff --git a/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp b/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp
new file mode 100644
index 0000000..40a670b
--- /dev/null
+++ b/src/lcd/extui/anycubic_i3mega/anycubic_extui.cpp
@@ -0,0 +1,124 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/**
+ * lcd/extui/anycubic_i3mega/anycubic_extui.cpp
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_I3MEGA)
+
+#include "anycubic_i3mega_lcd.h"
+#include "../ui_api.h"
+
+#include // for the ::tone() call
+
+namespace ExtUI {
+
+ void onStartup() { AnycubicTFT.OnSetup(); }
+ void onIdle() { AnycubicTFT.OnCommandScan(); }
+ void onPrinterKilled(FSTR_P const error, FSTR_P const component) { AnycubicTFT.OnKillTFT(); }
+ void onMediaInserted() { AnycubicTFT.OnSDCardStateChange(true); }
+ void onMediaError() { AnycubicTFT.OnSDCardError(); }
+ void onMediaRemoved() { AnycubicTFT.OnSDCardStateChange(false); }
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {
+ TERN_(SPEAKER, ::tone(BEEPER_PIN, frequency, duration));
+ }
+ void onPrintTimerStarted() { AnycubicTFT.OnPrintTimerStarted(); }
+ void onPrintTimerPaused() { AnycubicTFT.OnPrintTimerPaused(); }
+ void onPrintTimerStopped() { AnycubicTFT.OnPrintTimerStopped(); }
+ void onFilamentRunout(const extruder_t extruder) { AnycubicTFT.OnFilamentRunout(); }
+ void onUserConfirmRequired(const char * const msg) { AnycubicTFT.OnUserConfirmRequired(msg); }
+ void onStatusChanged(const char * const msg) {}
+
+ void onHomingStart() {}
+ void onHomingDone() {}
+ void onPrintDone() {}
+
+ void onFactoryReset() {}
+
+ void onStoreSettings(char *buff) {
+ // Called when saving to EEPROM (i.e. M500). If the ExtUI needs
+ // permanent data to be stored, it can write up to eeprom_data_size bytes
+ // into buff.
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= eeprom_data_size);
+ // memcpy(buff, &myDataStruct, sizeof(myDataStruct));
+ }
+
+ void onLoadSettings(const char *buff) {
+ // Called while loading settings from EEPROM. If the ExtUI
+ // needs to retrieve data, it should copy up to eeprom_data_size bytes
+ // from buff
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= eeprom_data_size);
+ // memcpy(&myDataStruct, buff, sizeof(myDataStruct));
+ }
+
+ void onPostprocessSettings() {
+ // Called after loading or resetting stored settings
+ }
+
+ void onSettingsStored(bool success) {
+ // Called after the entire EEPROM has been written,
+ // whether successful or not.
+ }
+
+ void onSettingsLoaded(bool success) {
+ // Called after the entire EEPROM has been read,
+ // whether successful or not.
+ }
+
+ #if HAS_MESH
+
+ void onLevelingStart() {}
+ void onLevelingDone() {}
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) {
+ // Called when any mesh points are updated
+ }
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, probe_state_t state) {
+ // Called when any mesh points are updated
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {
+ // Called on resume from power-loss
+ }
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ }
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // ANYCUBIC_LCD_I3MEGA
diff --git a/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp b/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp
new file mode 100644
index 0000000..0da8bb3
--- /dev/null
+++ b/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.cpp
@@ -0,0 +1,1026 @@
+/**
+ * anycubic_i3mega_lcd.cpp --- Support for Anycubic i3 Mega TFT
+ * Created by Christian Hopp on 09.12.17.
+ * Improved by David Ramiro
+ * Converted to ExtUI by John BouAntoun 21 June 2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(ANYCUBIC_LCD_I3MEGA)
+
+#include "anycubic_i3mega_lcd.h"
+#include "../ui_api.h"
+
+#include "../../../libs/numtostr.h"
+#include "../../../module/stepper.h" // for disable_all_steppers
+#include "../../../module/motion.h" // for quickstop_stepper, A20 read printing speed, feedrate_percentage
+#include "../../../MarlinCore.h" // for disable_steppers
+#include "../../../inc/MarlinConfig.h"
+
+// command sending macro's with debugging capability
+#define SEND_PGM(x) send_P(PSTR(x))
+#define SENDLINE_PGM(x) sendLine_P(PSTR(x))
+#define SEND_PGM_VAL(x,y) (send_P(PSTR(x)), sendLine(i16tostr3rj(y)))
+#define SEND(x) send(x)
+#define SENDLINE(x) sendLine(x)
+#if ENABLED(ANYCUBIC_LCD_DEBUG)
+ #define SENDLINE_DBG_PGM(x,y) do{ sendLine_P(PSTR(x)); SERIAL_ECHOLNPGM(y); }while(0)
+ #define SENDLINE_DBG_PGM_VAL(x,y,z) do{ sendLine_P(PSTR(x)); SERIAL_ECHOLNPGM(y, z); }while(0)
+#else
+ #define SENDLINE_DBG_PGM(x,y) sendLine_P(PSTR(x))
+ #define SENDLINE_DBG_PGM_VAL(x,y,z) sendLine_P(PSTR(x))
+#endif
+
+AnycubicTFTClass AnycubicTFT;
+
+char AnycubicTFTClass::TFTcmdbuffer[TFTBUFSIZE][TFT_MAX_CMD_SIZE];
+int AnycubicTFTClass::TFTbuflen = 0,
+ AnycubicTFTClass::TFTbufindr = 0,
+ AnycubicTFTClass::TFTbufindw = 0;
+char AnycubicTFTClass::serial3_char;
+int AnycubicTFTClass::serial3_count = 0;
+char* AnycubicTFTClass::TFTstrchr_pointer;
+uint8_t AnycubicTFTClass::SpecialMenu = false;
+AnycubicMediaPrintState AnycubicTFTClass::mediaPrintingState = AMPRINTSTATE_NOT_PRINTING;
+AnycubicMediaPauseState AnycubicTFTClass::mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+
+char AnycubicTFTClass::SelectedDirectory[30];
+char AnycubicTFTClass::SelectedFile[FILENAME_LENGTH];
+
+// Serial helpers
+static void sendNewLine() { LCD_SERIAL.write('\r'); LCD_SERIAL.write('\n'); }
+static void send(const char *str) { LCD_SERIAL.print(str); }
+static void send_P(PGM_P str) {
+ while (const char c = pgm_read_byte(str++))
+ LCD_SERIAL.write(c);
+}
+static void sendLine(const char *str) { send(str); sendNewLine(); }
+static void sendLine_P(PGM_P str) { send_P(str); sendNewLine(); }
+
+using namespace ExtUI;
+
+AnycubicTFTClass::AnycubicTFTClass() {}
+
+void AnycubicTFTClass::OnSetup() {
+ #ifndef LCD_BAUDRATE
+ #define LCD_BAUDRATE 115200
+ #endif
+ LCD_SERIAL.begin(LCD_BAUDRATE);
+
+ SENDLINE_DBG_PGM("J17", "TFT Serial Debug: Main board reset... J17"); // J17 Main board reset
+ delay_ms(10);
+
+ // Init the state of the key pins running on the TFT
+ #if BOTH(SDSUPPORT, HAS_SD_DETECT)
+ SET_INPUT_PULLUP(SD_DETECT_PIN);
+ #endif
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ SET_INPUT_PULLUP(FIL_RUNOUT1_PIN);
+ #endif
+
+ mediaPrintingState = AMPRINTSTATE_NOT_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+
+ // DoSDCardStateCheck();
+ SENDLINE_DBG_PGM("J12", "TFT Serial Debug: Ready... J12"); // J12 Ready
+ delay_ms(10);
+
+ DoFilamentRunoutCheck();
+ SelectedFile[0] = 0;
+
+ #if ENABLED(STARTUP_CHIME)
+ injectCommands(F("M300 P250 S554\nM300 P250 S554\nM300 P250 S740\nM300 P250 S554\nM300 P250 S740\nM300 P250 S554\nM300 P500 S831"));
+ #endif
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: Finished startup");
+ #endif
+}
+
+void AnycubicTFTClass::OnCommandScan() {
+ static millis_t nextStopCheck = 0; // used to slow the stopped print check down to reasonable times
+ const millis_t ms = millis();
+ if (ELAPSED(ms, nextStopCheck)) {
+ nextStopCheck = ms + 1000UL;
+ if (mediaPrintingState == AMPRINTSTATE_STOP_REQUESTED && IsNozzleHomed()) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: Finished stopping print, releasing motors ...");
+ #endif
+ mediaPrintingState = AMPRINTSTATE_NOT_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+ injectCommands(F("M84\nM27")); // disable stepper motors and force report of SD status
+ delay_ms(200);
+ // tell printer to release resources of print to indicate it is done
+ SENDLINE_DBG_PGM("J14", "TFT Serial Debug: SD Print Stopped... J14");
+ }
+ }
+
+ if (TFTbuflen < (TFTBUFSIZE - 1))
+ GetCommandFromTFT();
+
+ if (TFTbuflen) {
+ TFTbuflen = (TFTbuflen - 1);
+ TFTbufindr = (TFTbufindr + 1) % TFTBUFSIZE;
+ }
+}
+
+void AnycubicTFTClass::OnKillTFT() {
+ SENDLINE_DBG_PGM("J11", "TFT Serial Debug: Kill command... J11");
+}
+
+void AnycubicTFTClass::OnSDCardStateChange(bool isInserted) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: OnSDCardStateChange event triggered...", isInserted);
+ #endif
+ DoSDCardStateCheck();
+}
+
+void AnycubicTFTClass::OnSDCardError() {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: OnSDCardError event triggered...");
+ #endif
+ SENDLINE_DBG_PGM("J21", "TFT Serial Debug: On SD Card Error ... J21");
+}
+
+void AnycubicTFTClass::OnFilamentRunout() {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: FilamentRunout triggered...");
+ #endif
+ DoFilamentRunoutCheck();
+}
+
+void AnycubicTFTClass::OnUserConfirmRequired(const char * const msg) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: OnUserConfirmRequired triggered... ", msg);
+ #endif
+
+ #if ENABLED(SDSUPPORT)
+ /**
+ * Need to handle the process of following states
+ * "Nozzle Parked"
+ * "Load Filament"
+ * "Filament Purging..."
+ * "HeaterTimeout"
+ * "Reheat finished."
+ *
+ * NOTE: The only way to handle these states is strcmp_P with the msg unfortunately (very expensive)
+ */
+ if (strcmp_P(msg, PSTR("Nozzle Parked")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_PARKED;
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm SD print paused done... J18");
+ }
+ else if (strcmp_P(msg, PSTR("Load Filament")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_FILAMENT_OUT;
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm Filament is out... J18");
+ SENDLINE_DBG_PGM("J23", "TFT Serial Debug: UserConfirm Blocking filament prompt... J23");
+ }
+ else if (strcmp_P(msg, PSTR("Filament Purging...")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_PARKING;
+ // TODO: JBA I don't think J05 just disables the continue button, i think it injects a rogue M25. So taking this out
+ // disable continue button
+ // SENDLINE_DBG_PGM("J05", "TFT Serial Debug: UserConfirm SD Filament Purging... J05"); // J05 printing pause
+
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm Filament is purging... J18");
+ }
+ else if (strcmp_P(msg, PSTR("HeaterTimeout")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_HEATER_TIMEOUT;
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm SD Heater timeout... J18");
+ }
+ else if (strcmp_P(msg, PSTR("Reheat finished.")) == 0) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_REHEAT_FINISHED;
+ // enable continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: UserConfirm SD Reheat done... J18");
+ }
+ #endif
+}
+
+float AnycubicTFTClass::CodeValue() {
+ return (strtod(&TFTcmdbuffer[TFTbufindr][TFTstrchr_pointer - TFTcmdbuffer[TFTbufindr] + 1], nullptr));
+}
+
+bool AnycubicTFTClass::CodeSeen(char code) {
+ TFTstrchr_pointer = strchr(TFTcmdbuffer[TFTbufindr], code);
+ return !!TFTstrchr_pointer; // Return True if a character was found
+}
+
+bool AnycubicTFTClass::IsNozzleHomed() {
+ const float xPosition = getAxisPosition_mm((axis_t) X);
+ const float yPosition = getAxisPosition_mm((axis_t) Y);
+ return WITHIN(xPosition, X_MIN_POS - 0.1, X_MIN_POS + 0.1) &&
+ WITHIN(yPosition, Y_MIN_POS - 0.1, Y_MIN_POS + 0.1);
+}
+
+void AnycubicTFTClass::HandleSpecialMenu() {
+ /**
+ * NOTE: that the file selection command actual lowercases the entire selected file/foldername, so charracter comparisons need to be lowercase.
+ */
+ if (SelectedDirectory[0] == '<') {
+ switch (SelectedDirectory[1]) {
+ case 'e': // ""
+ SpecialMenu = false;
+ return;
+ break;
+
+ #if ENABLED(PROBE_MANUALLY)
+ case '0':
+ switch (SelectedDirectory[2]) {
+ case '1': // "<01ZUp0.1>"
+ SERIAL_ECHOLNPGM("Special Menu: Z Up 0.1");
+ injectCommands(F("G91\nG1 Z+0.1\nG90"));
+ break;
+
+ case '2': // "<02ZUp0.02>"
+ SERIAL_ECHOLNPGM("Special Menu: Z Up 0.02");
+ injectCommands(F("G91\nG1 Z+0.02\nG90"));
+ break;
+
+ case '3': // "<03ZDn0.02>"
+ SERIAL_ECHOLNPGM("Special Menu: Z Down 0.02");
+ injectCommands(F("G91\nG1 Z-0.02\nG90"));
+ break;
+
+ case '4': // "<04ZDn0.1>"
+ SERIAL_ECHOLNPGM("Special Menu: Z Down 0.1");
+ injectCommands(F("G91\nG1 Z-0.1\nG90"));
+ break;
+
+ case '5': // "<05PrehtBed>"
+ SERIAL_ECHOLNPGM("Special Menu: Preheat Bed");
+ injectCommands(F("M140 S65"));
+ break;
+
+ case '6': // "<06SMeshLvl>"
+ SERIAL_ECHOLNPGM("Special Menu: Start Mesh Leveling");
+ injectCommands(F("G29S1"));
+ break;
+
+ case '7': // "<07MeshNPnt>"
+ SERIAL_ECHOLNPGM("Special Menu: Next Mesh Point");
+ injectCommands(F("G29S2"));
+ break;
+
+ case '8': // "<08HtEndPID>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotend PID");
+ // need to dwell for half a second to give the fan a chance to start before the pid tuning starts
+ injectCommands(F("M106 S204\nG4 P500\nM303 E0 S215 C15 U1"));
+ break;
+
+ case '9': // "<09HtBedPID>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotbed Pid");
+ injectCommands(F("M303 E-1 S65 C6 U1"));
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case '1':
+ switch (SelectedDirectory[2]) {
+ case '0': // "<10FWDeflts>"
+ SERIAL_ECHOLNPGM("Special Menu: Load FW Defaults");
+ injectCommands(F("M502\nM300 P105 S1661\nM300 P210 S1108"));
+ break;
+
+ case '1': // "<11SvEEPROM>"
+ SERIAL_ECHOLNPGM("Special Menu: Save EEPROM");
+ injectCommands(F("M500\nM300 P105 S1108\nM300 P210 S1661"));
+ break;
+
+ default:
+ break;
+ }
+ break;
+ #else // if ENABLED(PROBE_MANUALLY)
+ case '0':
+ switch (SelectedDirectory[2]) {
+ case '1': // "<01PrehtBed>"
+ SERIAL_ECHOLNPGM("Special Menu: Preheat Bed");
+ injectCommands(F("M140 S65"));
+ break;
+
+ case '2': // "<02ABL>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Bed Leveling");
+ injectCommands(F("G29N"));
+ break;
+
+ case '3': // "<03HtendPID>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotend PID");
+ // need to dwell for half a second to give the fan a chance to start before the pid tuning starts
+ injectCommands(F("M106 S204\nG4 P500\nM303 E0 S215 C15 U1"));
+ break;
+
+ case '4': // "<04HtbedPID>"
+ SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotbed Pid");
+ injectCommands(F("M303 E-1 S65 C6 U1"));
+ break;
+
+ case '5': // "<05FWDeflts>"
+ SERIAL_ECHOLNPGM("Special Menu: Load FW Defaults");
+ injectCommands(F("M502\nM300 P105 S1661\nM300 P210 S1108"));
+ break;
+
+ case '6': // "<06SvEEPROM>"
+ SERIAL_ECHOLNPGM("Special Menu: Save EEPROM");
+ injectCommands(F("M500\nM300 P105 S1108\nM300 P210 S1661"));
+ break;
+
+ case '7': // <07SendM108>
+ SERIAL_ECHOLNPGM("Special Menu: Send User Confirmation");
+ injectCommands(F("M108"));
+ break;
+
+ default:
+ break;
+ }
+ break;
+ #endif // PROBE_MANUALLY
+
+ default:
+ break;
+ }
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ }
+ else {
+ SERIAL_ECHOPGM("TFT Serial Debug: Attempted to HandleSpecialMenu on non-special menu... ");
+ SERIAL_ECHOLN(SelectedDirectory);
+ #endif
+ }
+}
+
+void AnycubicTFTClass::RenderCurrentFileList() {
+ #if ENABLED(SDSUPPORT)
+ uint16_t selectedNumber = 0;
+ SelectedDirectory[0] = 0;
+ SelectedFile[0] = 0;
+ FileList currentFileList;
+
+ SENDLINE_PGM("FN "); // Filelist start
+
+ if (!isMediaInserted() && !SpecialMenu) {
+ SENDLINE_DBG_PGM("J02", "TFT Serial Debug: No SD Card mounted to render Current File List... J02");
+
+ SENDLINE_PGM("");
+ SENDLINE_PGM("");
+ }
+ else {
+ if (CodeSeen('S'))
+ selectedNumber = CodeValue();
+
+ if (SpecialMenu)
+ RenderSpecialMenu(selectedNumber);
+ else if (selectedNumber <= currentFileList.count())
+ RenderCurrentFolder(selectedNumber);
+ }
+ SENDLINE_PGM("END"); // Filelist stop
+ #endif // SDSUPPORT
+}
+
+void AnycubicTFTClass::RenderSpecialMenu(uint16_t selectedNumber) {
+ switch (selectedNumber) {
+ #if ENABLED(PROBE_MANUALLY)
+ case 0: // First Page
+ SENDLINE_PGM("<01ZUp0.1>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<02ZUp0.02>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<03ZDn0.02>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<04ZDn0.1>");
+ SENDLINE_PGM("");
+ break;
+
+ case 4: // Second Page
+ SENDLINE_PGM("<05PrehtBed>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<06SMeshLvl>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<07MeshNPnt>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<08HtEndPID>");
+ SENDLINE_PGM("");
+ break;
+
+ case 8: // Third Page
+ SENDLINE_PGM("<09HtBedPID>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<10FWDeflts>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<11SvEEPROM>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("");
+ break;
+ #else
+ case 0: // First Page
+ SENDLINE_PGM("<01PrehtBed>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<02ABL>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<03HtEndPID>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<04HtBedPID>");
+ SENDLINE_PGM("");
+ break;
+
+ case 4: // Second Page
+ SENDLINE_PGM("<05FWDeflts>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<06SvEEPROM>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("<07SendM108>");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("");
+ SENDLINE_PGM("");
+ break;
+
+ #endif // PROBE_MANUALLY
+
+ default:
+ break;
+ }
+}
+
+void AnycubicTFTClass::RenderCurrentFolder(uint16_t selectedNumber) {
+ FileList currentFileList;
+ uint16_t cnt = selectedNumber;
+ uint16_t max_files;
+ uint16_t dir_files = currentFileList.count();
+
+ if ((dir_files - selectedNumber) < 4)
+ max_files = dir_files;
+ else
+ max_files = selectedNumber + 3;
+
+ for (cnt = selectedNumber; cnt <= max_files; cnt++) {
+ if (cnt == 0) { // Special Entry
+ if (currentFileList.isAtRootDir()) {
+ SENDLINE_PGM("");
+ SENDLINE_PGM("");
+ }
+ else {
+ SENDLINE_PGM("/..");
+ SENDLINE_PGM("/..");
+ }
+ }
+ else {
+ currentFileList.seek(cnt - 1, false);
+
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLN(currentFileList.filename());
+ #endif
+ if (currentFileList.isDir()) {
+ SEND_PGM("/");
+ SENDLINE(currentFileList.shortFilename());
+ SEND_PGM("/");
+ SENDLINE(currentFileList.filename());
+
+ }
+ else {
+ SENDLINE(currentFileList.shortFilename());
+ SENDLINE(currentFileList.filename());
+ }
+ }
+ }
+}
+
+void AnycubicTFTClass::OnPrintTimerStarted() {
+ #if ENABLED(SDSUPPORT)
+ if (mediaPrintingState == AMPRINTSTATE_PRINTING)
+ SENDLINE_DBG_PGM("J04", "TFT Serial Debug: Starting SD Print... J04"); // J04 Starting Print
+
+ #endif
+}
+
+void AnycubicTFTClass::OnPrintTimerPaused() {
+ #if ENABLED(SDSUPPORT)
+ if (isPrintingFromMedia()) {
+ mediaPrintingState = AMPRINTSTATE_PAUSED;
+ mediaPauseState = AMPAUSESTATE_PARKING;
+ }
+ #endif
+}
+
+void AnycubicTFTClass::OnPrintTimerStopped() {
+ #if ENABLED(SDSUPPORT)
+ if (mediaPrintingState == AMPRINTSTATE_PRINTING) {
+ mediaPrintingState = AMPRINTSTATE_NOT_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+ SENDLINE_DBG_PGM("J14", "TFT Serial Debug: SD Print Completed... J14");
+ }
+ // otherwise it was stopped by the printer so don't send print completed signal to TFT
+ #endif
+}
+
+#define ROUND(val) int((val)+0.5f)
+
+void AnycubicTFTClass::GetCommandFromTFT() {
+ char *starpos = nullptr;
+ while (LCD_SERIAL.available() > 0 && TFTbuflen < TFTBUFSIZE) {
+ serial3_char = LCD_SERIAL.read();
+ if (serial3_char == '\n' ||
+ serial3_char == '\r' ||
+ serial3_char == ':' ||
+ serial3_count >= (TFT_MAX_CMD_SIZE - 1)
+ ) {
+
+ if (!serial3_count) return; // if empty line
+
+ TFTcmdbuffer[TFTbufindw][serial3_count] = 0; // terminate string
+
+ if ((strchr(TFTcmdbuffer[TFTbufindw], 'A') != nullptr)) {
+ int16_t a_command;
+ TFTstrchr_pointer = strchr(TFTcmdbuffer[TFTbufindw], 'A');
+ a_command = ((int)((strtod(&TFTcmdbuffer[TFTbufindw][TFTstrchr_pointer - TFTcmdbuffer[TFTbufindw] + 1], nullptr))));
+
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ if ((a_command > 7) && (a_command != 20)) // No debugging of status polls, please!
+ SERIAL_ECHOLNPGM("TFT Serial Command: ", TFTcmdbuffer[TFTbufindw]);
+ #endif
+
+ switch (a_command) {
+ case 0: { // A0 GET HOTEND TEMP
+ const celsius_float_t hotendActualTemp = getActualTemp_celsius(E0);
+ SEND_PGM_VAL("A0V ", ROUND(hotendActualTemp));
+ }
+ break;
+
+ case 1: { // A1 GET HOTEND TARGET TEMP
+ const celsius_float_t hotendTargetTemp = getTargetTemp_celsius(E0);
+ SEND_PGM_VAL("A1V ", ROUND(hotendTargetTemp));
+ }
+ break;
+
+ case 2: { // A2 GET HOTBED TEMP
+ const celsius_float_t heatedBedActualTemp = getActualTemp_celsius(BED);
+ SEND_PGM_VAL("A2V ", ROUND(heatedBedActualTemp));
+ }
+ break;
+
+ case 3: { // A3 GET HOTBED TARGET TEMP
+ const celsius_float_t heatedBedTargetTemp = getTargetTemp_celsius(BED);
+ SEND_PGM_VAL("A3V ", ROUND(heatedBedTargetTemp));
+ } break;
+
+ case 4: { // A4 GET FAN SPEED
+ SEND_PGM_VAL("A4V ", int(getActualFan_percent(FAN0)));
+ } break;
+
+ case 5: { // A5 GET CURRENT COORDINATE
+ const float xPosition = getAxisPosition_mm(X),
+ yPosition = getAxisPosition_mm(Y),
+ zPosition = getAxisPosition_mm(Z);
+ SEND_PGM("A5V X: "); LCD_SERIAL.print(xPosition);
+ SEND_PGM( " Y: "); LCD_SERIAL.print(yPosition);
+ SEND_PGM( " Z: "); LCD_SERIAL.print(zPosition);
+ SENDLINE_PGM("");
+ } break;
+
+ case 6: // A6 GET SD CARD PRINTING STATUS
+ #if ENABLED(SDSUPPORT)
+ if (isPrintingFromMedia()) {
+ SEND_PGM("A6V ");
+ if (isMediaInserted())
+ SENDLINE(ui8tostr3rj(getProgress_percent()));
+ else
+ SENDLINE_DBG_PGM("J02", "TFT Serial Debug: No SD Card mounted to return printing status... J02");
+ }
+ else
+ SENDLINE_PGM("A6V ---");
+ #endif
+ break;
+
+ case 7: { // A7 GET PRINTING TIME
+ const uint32_t elapsedSeconds = getProgress_seconds_elapsed();
+ SEND_PGM("A7V ");
+ if (elapsedSeconds != 0) { // print time
+ const uint32_t elapsedMinutes = elapsedSeconds / 60;
+ SEND(ui8tostr2(elapsedMinutes / 60));
+ SEND_PGM(" H ");
+ SEND(ui8tostr2(elapsedMinutes % 60));
+ SENDLINE_PGM(" M");
+ }
+ else
+ SENDLINE_PGM(" 999:999");
+ }
+ break;
+
+ case 8: // A8 GET SD LIST
+ #if ENABLED(SDSUPPORT)
+ SelectedFile[0] = 0;
+ RenderCurrentFileList();
+ #endif
+ break;
+
+ case 9: // A9 pause sd print
+ #if ENABLED(SDSUPPORT)
+ if (isPrintingFromMedia())
+ PausePrint();
+ #endif
+ break;
+
+ case 10: // A10 resume sd print
+ #if ENABLED(SDSUPPORT)
+ if (isPrintingFromMediaPaused())
+ ResumePrint();
+ #endif
+ break;
+
+ case 11: // A11 STOP SD PRINT
+ TERN_(SDSUPPORT, StopPrint());
+ break;
+
+ case 12: // A12 kill
+ kill(F(STR_ERR_KILLED));
+ break;
+
+ case 13: // A13 SELECTION FILE
+ #if ENABLED(SDSUPPORT)
+ if (isMediaInserted()) {
+ starpos = (strchr(TFTstrchr_pointer + 4, '*'));
+ if (TFTstrchr_pointer[4] == '/') {
+ strcpy(SelectedDirectory, TFTstrchr_pointer + 5);
+ SelectedFile[0] = 0;
+ SENDLINE_DBG_PGM("J21", "TFT Serial Debug: Clear file selection... J21 "); // J21 Not File Selected
+ SENDLINE_PGM("");
+ }
+ else if (TFTstrchr_pointer[4] == '<') {
+ strcpy(SelectedDirectory, TFTstrchr_pointer + 4);
+ SpecialMenu = true;
+ SelectedFile[0] = 0;
+ SENDLINE_DBG_PGM("J21", "TFT Serial Debug: Clear file selection... J21 "); // J21 Not File Selected
+ SENDLINE_PGM("");
+ }
+ else {
+ SelectedDirectory[0] = 0;
+
+ if (starpos) *(starpos - 1) = '\0';
+
+ strcpy(SelectedFile, TFTstrchr_pointer + 4);
+ SENDLINE_DBG_PGM_VAL("J20", "TFT Serial Debug: File Selected... J20 ", SelectedFile); // J20 File Selected
+ }
+ }
+ #endif
+ break;
+
+ case 14: // A14 START PRINTING
+ #if ENABLED(SDSUPPORT)
+ if (!isPrinting() && strlen(SelectedFile) > 0)
+ StartPrint();
+ #endif
+ break;
+
+ case 15: // A15 RESUMING FROM OUTAGE
+ // TODO: JBA implement resume form outage
+ break;
+
+ case 16: { // A16 set hotend temp
+ unsigned int tempvalue;
+ if (CodeSeen('S')) {
+ tempvalue = constrain(CodeValue(), 0, 275);
+ setTargetTemp_celsius(tempvalue, (extruder_t)E0);
+ }
+ else if (CodeSeen('C') && !isPrinting()) {
+ if (getAxisPosition_mm(Z) < 10)
+ injectCommands(F("G1 Z10")); // RASE Z AXIS
+ tempvalue = constrain(CodeValue(), 0, 275);
+ setTargetTemp_celsius(tempvalue, (extruder_t)E0);
+ }
+ }
+ break;
+
+ case 17: { // A17 set heated bed temp
+ unsigned int tempbed;
+ if (CodeSeen('S')) {
+ tempbed = constrain(CodeValue(), 0, 100);
+ setTargetTemp_celsius(tempbed, (heater_t)BED);
+ }
+ }
+ break;
+
+ case 18: { // A18 set fan speed
+ float fanPercent;
+ if (CodeSeen('S')) {
+ fanPercent = CodeValue();
+ fanPercent = constrain(fanPercent, 0, 100);
+ setTargetFan_percent(fanPercent, FAN0);
+ }
+ else
+ fanPercent = 100;
+
+ setTargetFan_percent(fanPercent, FAN0);
+ SENDLINE_PGM("");
+ }
+ break;
+
+ case 19: // A19 stop stepper drivers - sent on stop extrude command and on turn motors off command
+ if (!isPrinting()) {
+ quickstop_stepper();
+ stepper.disable_all_steppers();
+ }
+
+ SENDLINE_PGM("");
+ break;
+
+ case 20: // A20 read printing speed
+ if (CodeSeen('S'))
+ feedrate_percentage = constrain(CodeValue(), 40, 999);
+ else
+ SEND_PGM_VAL("A20V ", feedrate_percentage);
+ break;
+
+ case 21: // A21 all home
+ if (!isPrinting() && !isPrintingFromMediaPaused()) {
+ if (CodeSeen('X') || CodeSeen('Y') || CodeSeen('Z')) {
+ if (CodeSeen('X'))
+ injectCommands(F("G28X"));
+ if (CodeSeen('Y'))
+ injectCommands(F("G28Y"));
+ if (CodeSeen('Z'))
+ injectCommands(F("G28Z"));
+ }
+ else if (CodeSeen('C')) {
+ injectCommands_P(G28_STR);
+ }
+ }
+ break;
+
+ case 22: // A22 move X/Y/Z or extrude
+ if (!isPrinting()) {
+ float coorvalue;
+ unsigned int movespeed = 0;
+ char commandStr[30];
+ char fullCommandStr[38];
+
+ commandStr[0] = 0; // empty string
+ if (CodeSeen('F')) // Set feedrate
+ movespeed = CodeValue();
+
+ if (CodeSeen('X')) { // Move in X direction
+ coorvalue = CodeValue();
+ if ((coorvalue <= 0.2) && coorvalue > 0)
+ sprintf_P(commandStr, PSTR("G1 X0.1F%i"), movespeed);
+ else if ((coorvalue <= -0.1) && coorvalue > -1)
+ sprintf_P(commandStr, PSTR("G1 X-0.1F%i"), movespeed);
+ else
+ sprintf_P(commandStr, PSTR("G1 X%iF%i"), int(coorvalue), movespeed);
+ }
+ else if (CodeSeen('Y')) { // Move in Y direction
+ coorvalue = CodeValue();
+ if ((coorvalue <= 0.2) && coorvalue > 0)
+ sprintf_P(commandStr, PSTR("G1 Y0.1F%i"), movespeed);
+ else if ((coorvalue <= -0.1) && coorvalue > -1)
+ sprintf_P(commandStr, PSTR("G1 Y-0.1F%i"), movespeed);
+ else
+ sprintf_P(commandStr, PSTR("G1 Y%iF%i"), int(coorvalue), movespeed);
+ }
+ else if (CodeSeen('Z')) { // Move in Z direction
+ coorvalue = CodeValue();
+ if ((coorvalue <= 0.2) && coorvalue > 0)
+ sprintf_P(commandStr, PSTR("G1 Z0.1F%i"), movespeed);
+ else if ((coorvalue <= -0.1) && coorvalue > -1)
+ sprintf_P(commandStr, PSTR("G1 Z-0.1F%i"), movespeed);
+ else
+ sprintf_P(commandStr, PSTR("G1 Z%iF%i"), int(coorvalue), movespeed);
+ }
+ else if (CodeSeen('E')) { // Extrude
+ coorvalue = CodeValue();
+ if ((coorvalue <= 0.2) && coorvalue > 0)
+ sprintf_P(commandStr, PSTR("G1 E0.1F%i"), movespeed);
+ else if ((coorvalue <= -0.1) && coorvalue > -1)
+ sprintf_P(commandStr, PSTR("G1 E-0.1F%i"), movespeed);
+ else
+ sprintf_P(commandStr, PSTR("G1 E%iF500"), int(coorvalue));
+ }
+
+ if (strlen(commandStr) > 0) {
+ sprintf_P(fullCommandStr, PSTR("G91\n%s\nG90"), commandStr);
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOPGM("TFT Serial Debug: A22 Move final request with gcode... ");
+ SERIAL_ECHOLN(fullCommandStr);
+ #endif
+ injectCommands(fullCommandStr);
+ }
+ }
+ SENDLINE_PGM("");
+ break;
+
+ case 23: // A23 preheat pla
+ if (!isPrinting()) {
+ if (getAxisPosition_mm(Z) < 10)
+ injectCommands(F("G1 Z10")); // RASE Z AXIS
+
+ setTargetTemp_celsius(PREHEAT_1_TEMP_BED, (heater_t)BED);
+ setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, (extruder_t)E0);
+ SENDLINE_PGM("OK");
+ }
+ break;
+
+ case 24:// A24 preheat abs
+ if (!isPrinting()) {
+ if (getAxisPosition_mm(Z) < 10)
+ injectCommands(F("G1 Z10")); // RASE Z AXIS
+
+ setTargetTemp_celsius(PREHEAT_2_TEMP_BED, (heater_t)BED);
+ setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, (extruder_t)E0);
+ SENDLINE_PGM("OK");
+ }
+ break;
+
+ case 25: // A25 cool down
+ if (!isPrinting()) {
+ setTargetTemp_celsius(0, (heater_t) BED);
+ setTargetTemp_celsius(0, (extruder_t) E0);
+
+ SENDLINE_DBG_PGM("J12", "TFT Serial Debug: Cooling down... J12"); // J12 cool down
+ }
+ break;
+
+ case 26: // A26 refresh SD
+ #if ENABLED(SDSUPPORT)
+ if (isMediaInserted()) {
+ if (strlen(SelectedDirectory) > 0) {
+ FileList currentFileList;
+ if ((SelectedDirectory[0] == '.') && (SelectedDirectory[1] == '.')) {
+ currentFileList.upDir();
+ }
+ else {
+ if (SelectedDirectory[0] == '<')
+ HandleSpecialMenu();
+ else
+ currentFileList.changeDir(SelectedDirectory);
+ }
+ }
+ }
+ else {
+ SENDLINE_DBG_PGM("J02", "TFT Serial Debug: No SD Card mounted to refresh SD A26... J02");
+ }
+
+ SelectedDirectory[0] = 0;
+ #endif
+ break;
+
+ #if ENABLED(SERVO_ENDSTOPS)
+ case 27: break; // A27 servos angles adjust
+ #endif
+
+ case 28: // A28 filament test
+ if (CodeSeen('O'))
+ NOOP;
+ else if (CodeSeen('C'))
+ NOOP;
+ SENDLINE_PGM("");
+ break;
+
+ case 33: // A33 get version info
+ SEND_PGM("J33 ");
+ SENDLINE_PGM(DETAILED_BUILD_VERSION);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TFTbufindw = (TFTbufindw + 1) % TFTBUFSIZE;
+ TFTbuflen += 1;
+ serial3_count = 0; // clear buffer
+ }
+ else {
+ TFTcmdbuffer[TFTbufindw][serial3_count++] = serial3_char;
+ }
+ }
+}
+
+void AnycubicTFTClass::DoSDCardStateCheck() {
+ #if BOTH(SDSUPPORT, HAS_SD_DETECT)
+ bool isInserted = isMediaInserted();
+ if (isInserted)
+ SENDLINE_DBG_PGM("J00", "TFT Serial Debug: SD card state changed... isInserted");
+ else
+ SENDLINE_DBG_PGM("J01", "TFT Serial Debug: SD card state changed... !isInserted");
+
+ #endif
+}
+
+void AnycubicTFTClass::DoFilamentRunoutCheck() {
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ // NOTE: getFilamentRunoutState() only returns the runout state if the job is printing
+ // we want to actually check the status of the pin here, regardless of printstate
+ if (READ(FIL_RUNOUT1_PIN)) {
+ if (mediaPrintingState == AMPRINTSTATE_PRINTING || mediaPrintingState == AMPRINTSTATE_PAUSED || mediaPrintingState == AMPRINTSTATE_PAUSE_REQUESTED) {
+ // play tone to indicate filament is out
+ injectCommands(F("\nM300 P200 S1567\nM300 P200 S1174\nM300 P200 S1567\nM300 P200 S1174\nM300 P2000 S1567"));
+
+ // tell the user that the filament has run out and wait
+ SENDLINE_DBG_PGM("J23", "TFT Serial Debug: Blocking filament prompt... J23");
+ }
+ else {
+ SENDLINE_DBG_PGM("J15", "TFT Serial Debug: Non blocking filament runout... J15");
+ }
+ }
+ #endif // FILAMENT_RUNOUT_SENSOR
+}
+
+void AnycubicTFTClass::StartPrint() {
+ #if ENABLED(SDSUPPORT)
+ if (!isPrinting() && strlen(SelectedFile) > 0) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOPGM("TFT Serial Debug: About to print file ... ");
+ SERIAL_ECHO(isPrinting());
+ SERIAL_ECHOPGM(" ");
+ SERIAL_ECHOLN(SelectedFile);
+ #endif
+ mediaPrintingState = AMPRINTSTATE_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+ printFile(SelectedFile);
+ }
+ #endif // SDUPPORT
+}
+
+void AnycubicTFTClass::PausePrint() {
+ #if ENABLED(SDSUPPORT)
+ if (isPrintingFromMedia() && mediaPrintingState != AMPRINTSTATE_STOP_REQUESTED && mediaPauseState == AMPAUSESTATE_NOT_PAUSED) {
+ mediaPrintingState = AMPRINTSTATE_PAUSE_REQUESTED;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED; // need the userconfirm method to update pause state
+ SENDLINE_DBG_PGM("J05", "TFT Serial Debug: SD print pause started... J05"); // J05 printing pause
+
+ // for some reason pausing the print doesn't retract the extruder so force a manual one here
+ injectCommands(F("G91\nG1 E-2 F1800\nG90"));
+ pausePrint();
+ }
+ #endif
+}
+
+void AnycubicTFTClass::ResumePrint() {
+ #if ENABLED(SDSUPPORT)
+ #if ENABLED(FILAMENT_RUNOUT_SENSOR)
+ if (READ(FIL_RUNOUT1_PIN)) {
+ #if ENABLED(ANYCUBIC_LCD_DEBUG)
+ SERIAL_ECHOLNPGM("TFT Serial Debug: Resume Print with filament sensor still tripped... ");
+ #endif
+
+ // trigger the user message box
+ DoFilamentRunoutCheck();
+
+ // re-enable the continue button
+ SENDLINE_DBG_PGM("J18", "TFT Serial Debug: Resume Print with filament sensor still tripped... J18");
+ return;
+ }
+ #endif
+
+ if (mediaPauseState == AMPAUSESTATE_HEATER_TIMEOUT) {
+ mediaPauseState = AMPAUSESTATE_REHEATING;
+ // TODO: JBA I don't think J05 just disables the continue button, i think it injects a rogue M25. So taking this out
+ // // disable the continue button
+ // SENDLINE_DBG_PGM("J05", "TFT Serial Debug: Resume called with heater timeout... J05"); // J05 printing pause
+
+ // reheat the nozzle
+ setUserConfirmed();
+ }
+ else {
+ mediaPrintingState = AMPRINTSTATE_PRINTING;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+
+ SENDLINE_DBG_PGM("J04", "TFT Serial Debug: SD print resumed... J04"); // J04 printing form sd card now
+ resumePrint();
+ }
+ #endif
+}
+
+void AnycubicTFTClass::StopPrint() {
+ #if ENABLED(SDSUPPORT)
+ mediaPrintingState = AMPRINTSTATE_STOP_REQUESTED;
+ mediaPauseState = AMPAUSESTATE_NOT_PAUSED;
+ SENDLINE_DBG_PGM("J16", "TFT Serial Debug: SD print stop called... J16");
+
+ // for some reason stopping the print doesn't retract the extruder so force a manual one here
+ injectCommands(F("G91\nG1 E-2 F1800\nG90"));
+ stopPrint();
+ #endif
+}
+
+#endif // ANYCUBIC_LCD_I3MEGA
diff --git a/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.h b/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.h
new file mode 100644
index 0000000..8fcadc1
--- /dev/null
+++ b/src/lcd/extui/anycubic_i3mega/anycubic_i3mega_lcd.h
@@ -0,0 +1,95 @@
+/**
+ * anycubic_i3mega_lcd.h --- Support for Anycubic i3 Mega TFT
+ * Created by Christian Hopp on 09.12.17.
+ * Improved by David Ramiro
+ * Converted to ExtUI by John BouAntoun 21 June 2020
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#pragma once
+
+#include "../../../inc/MarlinConfigPre.h"
+#include "../../../sd/SdFatConfig.h" // for the FILENAME_LENGTH macro
+
+#define TFTBUFSIZE 4
+#define TFT_MAX_CMD_SIZE 96
+
+enum AnycubicMediaPrintState {
+ AMPRINTSTATE_NOT_PRINTING,
+ AMPRINTSTATE_PRINTING,
+ AMPRINTSTATE_PAUSE_REQUESTED,
+ AMPRINTSTATE_PAUSED,
+ AMPRINTSTATE_STOP_REQUESTED
+};
+
+enum AnycubicMediaPauseState {
+ AMPAUSESTATE_NOT_PAUSED,
+ AMPAUSESTATE_PARKING,
+ AMPAUSESTATE_PARKED,
+ AMPAUSESTATE_FILAMENT_OUT,
+ AMPAUSESTATE_FILAMENT_PURGING,
+ AMPAUSESTATE_HEATER_TIMEOUT,
+ AMPAUSESTATE_REHEATING,
+ AMPAUSESTATE_REHEAT_FINISHED
+};
+
+class AnycubicTFTClass {
+public:
+ AnycubicTFTClass();
+ static void OnSetup();
+ static void OnCommandScan();
+ static void OnKillTFT();
+ static void OnSDCardStateChange(bool);
+ static void OnSDCardError();
+ static void OnFilamentRunout();
+ static void OnUserConfirmRequired(const char *);
+ static void OnPrintTimerStarted();
+ static void OnPrintTimerPaused();
+ static void OnPrintTimerStopped();
+
+private:
+ static char TFTcmdbuffer[TFTBUFSIZE][TFT_MAX_CMD_SIZE];
+ static int TFTbuflen, TFTbufindr, TFTbufindw;
+ static char serial3_char;
+ static int serial3_count;
+ static char *TFTstrchr_pointer;
+ static uint8_t SpecialMenu;
+ static AnycubicMediaPrintState mediaPrintingState;
+ static AnycubicMediaPauseState mediaPauseState;
+
+ static float CodeValue();
+ static bool CodeSeen(char);
+ static bool IsNozzleHomed();
+ static void RenderCurrentFileList();
+ static void RenderSpecialMenu(uint16_t);
+ static void RenderCurrentFolder(uint16_t);
+ static void GetCommandFromTFT();
+ static void CheckSDCardChange();
+ static void CheckPauseState();
+ static void CheckPrintCompletion();
+ static void HandleSpecialMenu();
+ static void DoSDCardStateCheck();
+ static void DoFilamentRunoutCheck();
+ static void StartPrint();
+ static void PausePrint();
+ static void ResumePrint();
+ static void StopPrint();
+
+ static char SelectedDirectory[30];
+ static char SelectedFile[FILENAME_LENGTH];
+};
+
+extern AnycubicTFTClass AnycubicTFT;
+extern const char G28_STR[];
diff --git a/src/lcd/extui/dgus/DGUSDisplay.cpp b/src/lcd/extui/dgus/DGUSDisplay.cpp
new file mode 100644
index 0000000..0eb95bb
--- /dev/null
+++ b/src/lcd/extui/dgus/DGUSDisplay.cpp
@@ -0,0 +1,271 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if HAS_DGUS_LCD_CLASSIC
+
+#if HOTENDS > 2
+ #warning "More than 2 hotends not implemented on DGUS Display UI."
+#endif
+
+#include "../ui_api.h"
+
+#include "../../../MarlinCore.h"
+#include "../../../module/motion.h"
+#include "../../../gcode/queue.h"
+#include "../../../module/planner.h"
+#include "../../../libs/duration_t.h"
+#include "../../../module/printcounter.h"
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../feature/powerloss.h"
+#endif
+
+#include "DGUSDisplay.h"
+#include "DGUSVPVariable.h"
+#include "DGUSDisplayDef.h"
+
+DGUSDisplay dgusdisplay;
+
+#ifdef DEBUG_DGUSLCD_COMM
+ #define DEBUGLCDCOMM_ECHOPGM DEBUG_ECHOPGM
+#else
+ #define DEBUGLCDCOMM_ECHOPGM(...) NOOP
+#endif
+
+// Preamble... 2 Bytes, usually 0x5A 0xA5, but configurable
+constexpr uint8_t DGUS_HEADER1 = 0x5A;
+constexpr uint8_t DGUS_HEADER2 = 0xA5;
+
+constexpr uint8_t DGUS_CMD_WRITEVAR = 0x82;
+constexpr uint8_t DGUS_CMD_READVAR = 0x83;
+
+#if ENABLED(DEBUG_DGUSLCD)
+ bool dguslcd_local_debug; // = false;
+#endif
+
+void DGUSDisplay::InitDisplay() {
+ #ifndef LCD_BAUDRATE
+ #define LCD_BAUDRATE 115200
+ #endif
+ LCD_SERIAL.begin(LCD_BAUDRATE);
+
+ if (TERN1(POWER_LOSS_RECOVERY, !recovery.valid())) { // If no Power-Loss Recovery is needed...
+ TERN_(DGUS_LCD_UI_MKS, delay(LOGO_TIME_DELAY)); // Show the logo for a little while
+ }
+
+ RequestScreen(TERN(SHOW_BOOTSCREEN, DGUSLCD_SCREEN_BOOT, DGUSLCD_SCREEN_MAIN));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, const void *values, uint8_t valueslen, bool isstr) {
+ const char* myvalues = static_cast(values);
+ bool strend = !myvalues;
+ WriteHeader(adr, DGUS_CMD_WRITEVAR, valueslen);
+ while (valueslen--) {
+ char x;
+ if (!strend) x = *myvalues++;
+ if ((isstr && !x) || strend) {
+ strend = true;
+ x = ' ';
+ }
+ LCD_SERIAL.write(x);
+ }
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, uint16_t value) {
+ value = (value & 0xFFU) << 8U | (value >> 8U);
+ WriteVariable(adr, static_cast(&value), sizeof(uint16_t));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, int16_t value) {
+ value = (value & 0xFFU) << 8U | (value >> 8U);
+ WriteVariable(adr, static_cast(&value), sizeof(uint16_t));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, uint8_t value) {
+ WriteVariable(adr, static_cast(&value), sizeof(uint8_t));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, int8_t value) {
+ WriteVariable(adr, static_cast(&value), sizeof(int8_t));
+}
+
+void DGUSDisplay::WriteVariable(uint16_t adr, long value) {
+ union { long l; char lb[4]; } endian;
+ char tmp[4];
+ endian.l = value;
+ tmp[0] = endian.lb[3];
+ tmp[1] = endian.lb[2];
+ tmp[2] = endian.lb[1];
+ tmp[3] = endian.lb[0];
+ WriteVariable(adr, static_cast(&tmp), sizeof(long));
+}
+
+void DGUSDisplay::WriteVariablePGM(uint16_t adr, const void *values, uint8_t valueslen, bool isstr) {
+ const char* myvalues = static_cast(values);
+ bool strend = !myvalues;
+ WriteHeader(adr, DGUS_CMD_WRITEVAR, valueslen);
+ while (valueslen--) {
+ char x;
+ if (!strend) x = pgm_read_byte(myvalues++);
+ if ((isstr && !x) || strend) {
+ strend = true;
+ x = ' ';
+ }
+ LCD_SERIAL.write(x);
+ }
+}
+
+void DGUSDisplay::ProcessRx() {
+
+ #if ENABLED(SERIAL_STATS_RX_BUFFER_OVERRUNS)
+ if (!LCD_SERIAL.available() && LCD_SERIAL.buffer_overruns()) {
+ // Overrun, but reset the flag only when the buffer is empty
+ // We want to extract as many as valid datagrams possible...
+ DEBUG_ECHOPGM("OVFL");
+ rx_datagram_state = DGUS_IDLE;
+ //LCD_SERIAL.reset_rx_overun();
+ LCD_SERIAL.flush();
+ }
+ #endif
+
+ uint8_t receivedbyte;
+ while (LCD_SERIAL.available()) {
+ switch (rx_datagram_state) {
+
+ case DGUS_IDLE: // Waiting for the first header byte
+ receivedbyte = LCD_SERIAL.read();
+ //DEBUGLCDCOMM_ECHOPGM("< ", receivedbyte);
+ if (DGUS_HEADER1 == receivedbyte) rx_datagram_state = DGUS_HEADER1_SEEN;
+ break;
+
+ case DGUS_HEADER1_SEEN: // Waiting for the second header byte
+ receivedbyte = LCD_SERIAL.read();
+ //DEBUGLCDCOMM_ECHOPGM(" ", receivedbyte);
+ rx_datagram_state = (DGUS_HEADER2 == receivedbyte) ? DGUS_HEADER2_SEEN : DGUS_IDLE;
+ break;
+
+ case DGUS_HEADER2_SEEN: // Waiting for the length byte
+ rx_datagram_len = LCD_SERIAL.read();
+ //DEBUGLCDCOMM_ECHOPGM(" (", rx_datagram_len, ") ");
+
+ // Telegram min len is 3 (command and one word of payload)
+ rx_datagram_state = WITHIN(rx_datagram_len, 3, DGUS_RX_BUFFER_SIZE) ? DGUS_WAIT_TELEGRAM : DGUS_IDLE;
+ break;
+
+ case DGUS_WAIT_TELEGRAM: // wait for complete datagram to arrive.
+ if (LCD_SERIAL.available() < rx_datagram_len) return;
+
+ Initialized = true; // We've talked to it, so we defined it as initialized.
+ uint8_t command = LCD_SERIAL.read();
+
+ //DEBUGLCDCOMM_ECHOPGM("# ", command);
+
+ uint8_t readlen = rx_datagram_len - 1; // command is part of len.
+ unsigned char tmp[rx_datagram_len - 1];
+ unsigned char *ptmp = tmp;
+ while (readlen--) {
+ receivedbyte = LCD_SERIAL.read();
+ //DEBUGLCDCOMM_ECHOPGM(" ", receivedbyte);
+ *ptmp++ = receivedbyte;
+ }
+ //DEBUGLCDCOMM_ECHOPGM(" # ");
+ // mostly we'll get this: 5A A5 03 82 4F 4B -- ACK on 0x82, so discard it.
+ if (command == DGUS_CMD_WRITEVAR && 'O' == tmp[0] && 'K' == tmp[1]) {
+ //DEBUGLCDCOMM_ECHOPGM(">");
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ /* AutoUpload, (and answer to) Command 0x83 :
+ | tmp[0 1 2 3 4 ... ]
+ | Example 5A A5 06 83 20 01 01 78 01 ……
+ | / / | | \ / | \ \
+ | Header | | | | \_____\_ DATA (Words!)
+ | DatagramLen / VPAdr |
+ | Command DataLen (in Words) */
+ if (command == DGUS_CMD_READVAR) {
+ const uint16_t vp = tmp[0] << 8 | tmp[1];
+ //const uint8_t dlen = tmp[2] << 1; // Convert to Bytes. (Display works with words)
+ //DEBUG_ECHOPGM(" vp=", vp, " dlen=", dlen);
+ DGUS_VP_Variable ramcopy;
+ if (populate_VPVar(vp, &ramcopy)) {
+ if (ramcopy.set_by_display_handler)
+ ramcopy.set_by_display_handler(ramcopy, &tmp[3]);
+ else
+ DEBUG_ECHOLNPGM(" VPVar found, no handler.");
+ }
+ else
+ DEBUG_ECHOLNPGM(" VPVar not found:", vp);
+
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ // discard anything else
+ rx_datagram_state = DGUS_IDLE;
+ }
+ }
+}
+
+size_t DGUSDisplay::GetFreeTxBuffer() { return SERIAL_GET_TX_BUFFER_FREE(); }
+
+void DGUSDisplay::WriteHeader(uint16_t adr, uint8_t cmd, uint8_t payloadlen) {
+ LCD_SERIAL.write(DGUS_HEADER1);
+ LCD_SERIAL.write(DGUS_HEADER2);
+ LCD_SERIAL.write(payloadlen + 3);
+ LCD_SERIAL.write(cmd);
+ LCD_SERIAL.write(adr >> 8);
+ LCD_SERIAL.write(adr & 0xFF);
+}
+
+void DGUSDisplay::WritePGM(const char str[], uint8_t len) {
+ while (len--) LCD_SERIAL.write(pgm_read_byte(str++));
+}
+
+void DGUSDisplay::loop() {
+ // Protect against recursion. ProcessRx() may indirectly call idle() when injecting G-code commands.
+ if (!no_reentrance) {
+ no_reentrance = true;
+ ProcessRx();
+ no_reentrance = false;
+ }
+}
+
+rx_datagram_state_t DGUSDisplay::rx_datagram_state = DGUS_IDLE;
+uint8_t DGUSDisplay::rx_datagram_len = 0;
+bool DGUSDisplay::Initialized = false,
+ DGUSDisplay::no_reentrance = false;
+
+// A SW memory barrier, to ensure GCC does not overoptimize loops
+#define sw_barrier() asm volatile("": : :"memory");
+
+bool populate_VPVar(const uint16_t VP, DGUS_VP_Variable * const ramcopy) {
+ //DEBUG_ECHOPGM("populate_VPVar ", VP);
+ const DGUS_VP_Variable *pvp = DGUSLCD_FindVPVar(VP);
+ //DEBUG_ECHOLNPGM(" pvp ", (uint16_t )pvp);
+ if (!pvp) return false;
+ memcpy_P(ramcopy, pvp, sizeof(DGUS_VP_Variable));
+ return true;
+}
+
+#endif // HAS_DGUS_LCD_CLASSIC
diff --git a/src/lcd/extui/dgus/DGUSDisplay.h b/src/lcd/extui/dgus/DGUSDisplay.h
new file mode 100644
index 0000000..b6773db
--- /dev/null
+++ b/src/lcd/extui/dgus/DGUSDisplay.h
@@ -0,0 +1,125 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/dgus/DGUSDisplay.h
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#include // size_t
+
+//#define DEBUG_DGUSLCD
+//#define DEBUG_DGUSLCD_COMM
+
+#if HAS_BED_PROBE
+ #include "../../../module/probe.h"
+#endif
+#include "DGUSVPVariable.h"
+
+enum DGUSLCD_Screens : uint8_t;
+
+//#define DEBUG_DGUSLCD
+#define DEBUG_OUT ENABLED(DEBUG_DGUSLCD)
+#include "../../../core/debug_out.h"
+
+typedef enum : uint8_t {
+ DGUS_IDLE, //< waiting for DGUS_HEADER1.
+ DGUS_HEADER1_SEEN, //< DGUS_HEADER1 received
+ DGUS_HEADER2_SEEN, //< DGUS_HEADER2 received
+ DGUS_WAIT_TELEGRAM, //< LEN received, Waiting for to receive all bytes.
+} rx_datagram_state_t;
+
+constexpr uint16_t swap16(const uint16_t value) { return (value & 0xFFU) << 8U | (value >> 8U); }
+
+// Low-Level access to the display.
+class DGUSDisplay {
+public:
+
+ DGUSDisplay() = default;
+
+ static void InitDisplay();
+
+ // Variable access.
+ static void WriteVariable(uint16_t adr, const void *values, uint8_t valueslen, bool isstr=false);
+ static void WriteVariablePGM(uint16_t adr, const void *values, uint8_t valueslen, bool isstr=false);
+ static void WriteVariable(uint16_t adr, int16_t value);
+ static void WriteVariable(uint16_t adr, uint16_t value);
+ static void WriteVariable(uint16_t adr, uint8_t value);
+ static void WriteVariable(uint16_t adr, int8_t value);
+ static void WriteVariable(uint16_t adr, long value);
+
+ // Utility functions for bridging ui_api and dbus
+ template
+ static void SetVariable(DGUS_VP_Variable &var) {
+ WriteVariable(var.VP, (WireType)Getter(selector));
+ }
+
+ template
+ static void GetVariable(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
+ Setter(newvalue, selector);
+ }
+
+ // Until now I did not need to actively read from the display. That's why there is no ReadVariable
+ // (I extensively use the auto upload of the display)
+
+ // Force display into another screen.
+ // (And trigger update of containing VPs)
+ // (to implement a pop up message, which may not be nested)
+ static void RequestScreen(DGUSLCD_Screens screen);
+
+ // Periodic tasks, eg. Rx-Queue handling.
+ static void loop();
+
+public:
+ // Helper for users of this class to estimate if an interaction would be blocking.
+ static size_t GetFreeTxBuffer();
+
+ // Checks two things: Can we confirm the presence of the display and has we initialized it.
+ // (both boils down that the display answered to our chatting)
+ static bool isInitialized() { return Initialized; }
+
+private:
+ static void WriteHeader(uint16_t adr, uint8_t cmd, uint8_t payloadlen);
+ static void WritePGM(const char str[], uint8_t len);
+ static void ProcessRx();
+
+ static rx_datagram_state_t rx_datagram_state;
+ static uint8_t rx_datagram_len;
+ static bool Initialized, no_reentrance;
+};
+
+extern DGUSDisplay dgusdisplay;
+
+// compile-time x^y
+constexpr float cpow(const float x, const int y) { return y == 0 ? 1.0 : x * cpow(x, y - 1); }
+
+///
+const uint16_t* DGUSLCD_FindScreenVPMapList(uint8_t screen);
+
+/// Find the flash address of a DGUS_VP_Variable for the VP.
+const DGUS_VP_Variable* DGUSLCD_FindVPVar(const uint16_t vp);
+
+/// Helper to populate a DGUS_VP_Variable for a given VP. Return false if not found.
+bool populate_VPVar(const uint16_t VP, DGUS_VP_Variable * const ramcopy);
diff --git a/src/lcd/extui/dgus/DGUSDisplayDef.h b/src/lcd/extui/dgus/DGUSDisplayDef.h
new file mode 100644
index 0000000..9cbcf0d
--- /dev/null
+++ b/src/lcd/extui/dgus/DGUSDisplayDef.h
@@ -0,0 +1,57 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/dgus/DGUSDisplayDef.h
+ * Defines the interaction between Marlin and the display firmware
+ */
+
+#include "DGUSVPVariable.h"
+
+#include
+
+// Information on which screen which VP is displayed.
+// As this is a sparse table, two arrays are needed:
+// one to list the VPs of one screen and one to map screens to the lists.
+// (Strictly this would not be necessary, but allows to only send data the display needs and reducing load on Marlin)
+struct VPMapping {
+ const uint8_t screen;
+ const uint16_t *VPList; // The list is null-terminated.
+};
+
+extern const struct VPMapping VPMap[];
+
+// List of VPs handled by Marlin / The Display.
+extern const struct DGUS_VP_Variable ListOfVP[];
+
+#include "../../../inc/MarlinConfig.h"
+
+#if ENABLED(DGUS_LCD_UI_ORIGIN)
+ #include "origin/DGUSDisplayDef.h"
+#elif ENABLED(DGUS_LCD_UI_MKS)
+ #include "mks/DGUSDisplayDef.h"
+#elif ENABLED(DGUS_LCD_UI_FYSETC)
+ #include "fysetc/DGUSDisplayDef.h"
+#elif ENABLED(DGUS_LCD_UI_HIPRECY)
+ #include "hiprecy/DGUSDisplayDef.h"
+#endif
diff --git a/src/lcd/extui/dgus/DGUSScreenHandler.cpp b/src/lcd/extui/dgus/DGUSScreenHandler.cpp
new file mode 100644
index 0000000..0f34d76
--- /dev/null
+++ b/src/lcd/extui/dgus/DGUSScreenHandler.cpp
@@ -0,0 +1,738 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if HAS_DGUS_LCD_CLASSIC
+
+#include "DGUSScreenHandler.h"
+
+#include "../../../MarlinCore.h"
+#include "../../../gcode/queue.h"
+#include "../../../libs/duration_t.h"
+#include "../../../module/settings.h"
+#include "../../../module/temperature.h"
+#include "../../../module/motion.h"
+#include "../../../module/planner.h"
+#include "../../../module/printcounter.h"
+#include "../../../sd/cardreader.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../feature/powerloss.h"
+#endif
+
+DGUSScreenHandlerClass ScreenHandler;
+
+uint16_t DGUSScreenHandler::ConfirmVP;
+
+DGUSLCD_Screens DGUSScreenHandler::current_screen;
+DGUSLCD_Screens DGUSScreenHandler::past_screens[NUM_PAST_SCREENS];
+uint8_t DGUSScreenHandler::update_ptr;
+uint16_t DGUSScreenHandler::skipVP;
+bool DGUSScreenHandler::ScreenComplete;
+
+void (*DGUSScreenHandler::confirm_action_cb)() = nullptr;
+
+#if ENABLED(SDSUPPORT)
+ int16_t DGUSScreenHandler::top_file = 0,
+ DGUSScreenHandler::file_to_print = 0;
+ ExtUI::FileList filelist;
+#endif
+
+#if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ filament_data_t filament_data;
+#endif
+
+void DGUSScreenHandler::sendinfoscreen(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool l4inflash) {
+ DGUS_VP_Variable ramcopy;
+ if (populate_VPVar(VP_MSGSTR1, &ramcopy)) {
+ ramcopy.memadr = (void*) line1;
+ l1inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+ if (populate_VPVar(VP_MSGSTR2, &ramcopy)) {
+ ramcopy.memadr = (void*) line2;
+ l2inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+ if (populate_VPVar(VP_MSGSTR3, &ramcopy)) {
+ ramcopy.memadr = (void*) line3;
+ l3inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+ #ifdef VP_MSGSTR4
+ if (populate_VPVar(VP_MSGSTR4, &ramcopy)) {
+ ramcopy.memadr = (void*) line4;
+ l4inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+ #endif
+}
+
+void DGUSScreenHandler::HandleUserConfirmationPopUp(uint16_t VP, PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4, bool l1, bool l2, bool l3, bool l4) {
+ if (current_screen == DGUSLCD_SCREEN_CONFIRM) // Already showing a pop up, so we need to cancel that first.
+ PopToOldScreen();
+
+ ConfirmVP = VP;
+ sendinfoscreen(line1, line2, line3, line4, l1, l2, l3, l4);
+ GotoScreen(DGUSLCD_SCREEN_CONFIRM);
+}
+
+void DGUSScreenHandler::setstatusmessage(const char *msg) {
+ DGUS_VP_Variable ramcopy;
+ if (populate_VPVar(VP_M117, &ramcopy)) {
+ ramcopy.memadr = (void*) msg;
+ DGUSLCD_SendStringToDisplay(ramcopy);
+ }
+}
+
+void DGUSScreenHandler::setstatusmessagePGM(PGM_P const msg) {
+ DGUS_VP_Variable ramcopy;
+ if (populate_VPVar(VP_M117, &ramcopy)) {
+ ramcopy.memadr = (void*) msg;
+ DGUSLCD_SendStringToDisplayPGM(ramcopy);
+ }
+}
+
+// Send an 8 bit or 16 bit value to the display.
+void DGUSScreenHandler::DGUSLCD_SendWordValueToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ //DEBUG_ECHOPGM(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
+ //DEBUG_ECHOLNPGM(" data ", *(uint16_t *)var.memadr);
+ if (var.size > 1)
+ dgusdisplay.WriteVariable(var.VP, *(int16_t*)var.memadr);
+ else
+ dgusdisplay.WriteVariable(var.VP, *(int8_t*)var.memadr);
+ }
+}
+
+// Send an uint8_t between 0 and 255 to the display, but scale to a percentage (0..100)
+void DGUSScreenHandler::DGUSLCD_SendPercentageToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ //DEBUG_ECHOPGM(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
+ //DEBUG_ECHOLNPGM(" data ", *(uint16_t *)var.memadr);
+ uint16_t tmp = *(uint8_t *) var.memadr + 1; // +1 -> avoid rounding issues for the display.
+ tmp = map(tmp, 0, 255, 0, 100);
+ dgusdisplay.WriteVariable(var.VP, tmp);
+ }
+}
+
+// Send the current print progress to the display.
+void DGUSScreenHandler::DGUSLCD_SendPrintProgressToDisplay(DGUS_VP_Variable &var) {
+ //DEBUG_ECHOPGM(" DGUSLCD_SendPrintProgressToDisplay ", var.VP);
+ uint16_t tmp = ExtUI::getProgress_percent();
+ //DEBUG_ECHOLNPGM(" data ", tmp);
+ dgusdisplay.WriteVariable(var.VP, tmp);
+}
+
+// Send the current print time to the display.
+// It is using a hex display for that: It expects BSD coded data in the format xxyyzz
+void DGUSScreenHandler::DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var) {
+ duration_t elapsed = print_job_timer.duration();
+ char buf[32];
+ elapsed.toString(buf);
+ dgusdisplay.WriteVariable(VP_PrintTime, buf, var.size, true);
+}
+
+// Send an uint8_t between 0 and 100 to a variable scale to 0..255
+void DGUSScreenHandler::DGUSLCD_PercentageToUint8(DGUS_VP_Variable &var, void *val_ptr) {
+ if (var.memadr) {
+ uint16_t value = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("FAN value get:", value);
+ *(uint8_t*)var.memadr = map(constrain(value, 0, 100), 0, 100, 0, 255);
+ DEBUG_ECHOLNPGM("FAN value change:", *(uint8_t*)var.memadr);
+ }
+}
+
+// Sends a (RAM located) string to the DGUS Display
+// (Note: The DGUS Display does not clear after the \0, you have to
+// overwrite the remainings with spaces.// var.size has the display buffer size!
+void DGUSScreenHandler::DGUSLCD_SendStringToDisplay(DGUS_VP_Variable &var) {
+ char *tmp = (char*) var.memadr;
+ dgusdisplay.WriteVariable(var.VP, tmp, var.size, true);
+}
+
+// Sends a (flash located) string to the DGUS Display
+// (Note: The DGUS Display does not clear after the \0, you have to
+// overwrite the remainings with spaces.// var.size has the display buffer size!
+void DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(DGUS_VP_Variable &var) {
+ char *tmp = (char*) var.memadr;
+ dgusdisplay.WriteVariablePGM(var.VP, tmp, var.size, true);
+}
+
+#if HAS_PID_HEATING
+ void DGUSScreenHandler::DGUSLCD_SendTemperaturePID(DGUS_VP_Variable &var) {
+ float value = *(float *)var.memadr;
+ value /= 10;
+ float valuesend = 0;
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_PID_P: valuesend = value; break;
+ case VP_E0_PID_I: valuesend = unscalePID_i(value); break;
+ case VP_E0_PID_D: valuesend = unscalePID_d(value); break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_PID_P: valuesend = value; break;
+ case VP_E1_PID_I: valuesend = unscalePID_i(value); break;
+ case VP_E1_PID_D: valuesend = unscalePID_d(value); break;
+ #endif
+ #if HAS_HEATED_BED
+ case VP_BED_PID_P: valuesend = value; break;
+ case VP_BED_PID_I: valuesend = unscalePID_i(value); break;
+ case VP_BED_PID_D: valuesend = unscalePID_d(value); break;
+ #endif
+ }
+
+ valuesend *= cpow(10, 1);
+ union { int16_t i; char lb[2]; } endian;
+
+ char tmp[2];
+ endian.i = valuesend;
+ tmp[0] = endian.lb[1];
+ tmp[1] = endian.lb[0];
+ dgusdisplay.WriteVariable(var.VP, tmp, 2);
+ }
+#endif
+
+#if ENABLED(PRINTCOUNTER)
+
+ // Send the accumulate print time to the display.
+ // It is using a hex display for that: It expects BSD coded data in the format xxyyzz
+ void DGUSScreenHandler::DGUSLCD_SendPrintAccTimeToDisplay(DGUS_VP_Variable &var) {
+ printStatistics state = print_job_timer.getStats();
+ char buf[22];
+ duration_t elapsed = state.printTime;
+ elapsed.toString(buf);
+ dgusdisplay.WriteVariable(VP_PrintAccTime, buf, var.size, true);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SendPrintsTotalToDisplay(DGUS_VP_Variable &var) {
+ printStatistics state = print_job_timer.getStats();
+ char buf[10];
+ sprintf_P(buf, PSTR("%u"), state.totalPrints);
+ dgusdisplay.WriteVariable(VP_PrintsTotal, buf, var.size, true);
+ }
+
+#endif
+
+// Send fan status value to the display.
+#if HAS_FAN
+
+ void DGUSScreenHandler::DGUSLCD_SendFanStatusToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ DEBUG_ECHOPGM(" DGUSLCD_SendFanStatusToDisplay ", var.VP);
+ DEBUG_ECHOLNPGM(" data ", *(uint8_t *)var.memadr);
+ uint16_t data_to_send = 0;
+ if (*(uint8_t *) var.memadr) data_to_send = 1;
+ dgusdisplay.WriteVariable(var.VP, data_to_send);
+ }
+ }
+
+#endif
+
+// Send heater status value to the display.
+void DGUSScreenHandler::DGUSLCD_SendHeaterStatusToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ DEBUG_ECHOPGM(" DGUSLCD_SendHeaterStatusToDisplay ", var.VP);
+ DEBUG_ECHOLNPGM(" data ", *(int16_t *)var.memadr);
+ uint16_t data_to_send = 0;
+ if (*(int16_t *) var.memadr) data_to_send = 1;
+ dgusdisplay.WriteVariable(var.VP, data_to_send);
+ }
+}
+
+#if ENABLED(DGUS_UI_WAITING)
+
+ void DGUSScreenHandler::DGUSLCD_SendWaitingStatusToDisplay(DGUS_VP_Variable &var) {
+ // In FYSETC UI design there are 10 statuses to loop
+ static uint16_t period = 0;
+ static uint16_t index = 0;
+ //DEBUG_ECHOPGM(" DGUSLCD_SendWaitingStatusToDisplay ", var.VP);
+ //DEBUG_ECHOLNPGM(" data ", swap16(index));
+ if (period++ > DGUS_UI_WAITING_STATUS_PERIOD) {
+ dgusdisplay.WriteVariable(var.VP, index);
+ //DEBUG_ECHOLNPGM(" data ", swap16(index));
+ if (++index >= DGUS_UI_WAITING_STATUS) index = 0;
+ period = 0;
+ }
+ }
+
+#endif
+
+#if ENABLED(SDSUPPORT)
+
+ void DGUSScreenHandler::ScreenChangeHookIfSD(DGUS_VP_Variable &var, void *val_ptr) {
+ // default action executed when there is a SD card, but not printing
+ if (ExtUI::isMediaInserted() && !ExtUI::isPrintingFromMedia()) {
+ ScreenChangeHook(var, val_ptr);
+ dgusdisplay.RequestScreen(current_screen);
+ return;
+ }
+
+ // if we are printing, we jump to two screens after the requested one.
+ // This should host e.g a print pause / print abort / print resume dialog.
+ // This concept allows to recycle this hook for other file
+ if (ExtUI::isPrintingFromMedia() && !card.flag.abort_sd_printing) {
+ GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
+ return;
+ }
+
+ // Don't let the user in the dark why there is no reaction.
+ if (!ExtUI::isMediaInserted()) {
+ setstatusmessagePGM(GET_TEXT(MSG_NO_MEDIA));
+ return;
+ }
+ if (card.flag.abort_sd_printing) {
+ setstatusmessagePGM(GET_TEXT(MSG_MEDIA_ABORTING));
+ return;
+ }
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_ScrollFilelist(DGUS_VP_Variable& var, void *val_ptr) {
+ auto old_top = top_file;
+ const int16_t scroll = (int16_t)swap16(*(uint16_t*)val_ptr);
+ if (scroll) {
+ top_file += scroll;
+ DEBUG_ECHOPGM("new topfile calculated:", top_file);
+ if (top_file < 0) {
+ top_file = 0;
+ DEBUG_ECHOLNPGM("Top of filelist reached");
+ }
+ else {
+ int16_t max_top = filelist.count() - DGUS_SD_FILESPERSCREEN;
+ NOLESS(max_top, 0);
+ NOMORE(top_file, max_top);
+ }
+ DEBUG_ECHOPGM("new topfile adjusted:", top_file);
+ }
+ else if (!filelist.isAtRootDir()) {
+ IF_DISABLED(DGUS_LCD_UI_MKS, filelist.upDir());
+ top_file = 0;
+ ForceCompleteUpdate();
+ }
+
+ if (old_top != top_file) ForceCompleteUpdate();
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_ReallyAbort(DGUS_VP_Variable &var, void *val_ptr) {
+ ExtUI::stopPrint();
+ GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_PrintTune(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
+ GotoScreen(DGUSLCD_SCREEN_SDPRINTTUNE);
+ }
+
+ void DGUSScreenHandler::SDCardError() {
+ DGUSScreenHandler::SDCardRemoved();
+ sendinfoscreen(F("NOTICE"), nullptr, F("SD card error"), nullptr, true, true, true, true);
+ SetupConfirmAction(nullptr);
+ GotoScreen(DGUSLCD_SCREEN_POPUP);
+ }
+
+#endif // SDSUPPORT
+
+void DGUSScreenHandler::ScreenConfirmedOK(DGUS_VP_Variable &var, void *val_ptr) {
+ DGUS_VP_Variable ramcopy;
+ if (!populate_VPVar(ConfirmVP, &ramcopy)) return;
+ if (ramcopy.set_by_display_handler) ramcopy.set_by_display_handler(ramcopy, val_ptr);
+}
+
+const uint16_t* DGUSLCD_FindScreenVPMapList(uint8_t screen) {
+ const uint16_t *ret;
+ const struct VPMapping *map = VPMap;
+ while ((ret = (uint16_t*) pgm_read_ptr(&(map->VPList)))) {
+ if (pgm_read_byte(&(map->screen)) == screen) return ret;
+ map++;
+ }
+ return nullptr;
+}
+
+const DGUS_VP_Variable* DGUSLCD_FindVPVar(const uint16_t vp) {
+ const DGUS_VP_Variable *ret = ListOfVP;
+ do {
+ const uint16_t vpcheck = pgm_read_word(&(ret->VP));
+ if (vpcheck == 0) break;
+ if (vpcheck == vp) return ret;
+ ++ret;
+ } while (1);
+
+ DEBUG_ECHOLNPGM("FindVPVar NOT FOUND ", vp);
+ return nullptr;
+}
+
+void DGUSScreenHandler::ScreenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!ExtUI::isPrinting()) {
+ ScreenChangeHook(var, val_ptr);
+ dgusdisplay.RequestScreen(current_screen);
+ }
+}
+
+void DGUSScreenHandler::HandleAllHeatersOff(DGUS_VP_Variable &var, void *val_ptr) {
+ thermalManager.disable_all_heaters();
+ ForceCompleteUpdate(); // hint to send all data.
+}
+
+void DGUSScreenHandler::HandleTemperatureChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ celsius_t newvalue = swap16(*(uint16_t*)val_ptr);
+ celsius_t acceptedvalue;
+
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_T_E0_Set:
+ NOMORE(newvalue, HEATER_0_MAXTEMP);
+ thermalManager.setTargetHotend(newvalue, 0);
+ acceptedvalue = thermalManager.degTargetHotend(0);
+ break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_T_E1_Set:
+ NOMORE(newvalue, HEATER_1_MAXTEMP);
+ thermalManager.setTargetHotend(newvalue, 1);
+ acceptedvalue = thermalManager.degTargetHotend(1);
+ break;
+ #endif
+ #if HAS_HEATED_BED
+ case VP_T_Bed_Set:
+ NOMORE(newvalue, BED_MAXTEMP);
+ thermalManager.setTargetBed(newvalue);
+ acceptedvalue = thermalManager.degTargetBed();
+ break;
+ #endif
+ }
+
+ // reply to display the new value to update the view if the new value was rejected by the Thermal Manager.
+ if (newvalue != acceptedvalue && var.send_to_display_handler) var.send_to_display_handler(var);
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandler::HandleFlowRateChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ #if HAS_EXTRUDERS
+ uint16_t newvalue = swap16(*(uint16_t*)val_ptr);
+ uint8_t target_extruder;
+ switch (var.VP) {
+ default: return;
+ case VP_Flowrate_E0: target_extruder = 0; break;
+ #if HAS_MULTI_EXTRUDER
+ case VP_Flowrate_E1: target_extruder = 1; break;
+ #endif
+ }
+
+ planner.set_flow(target_extruder, newvalue);
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ #else
+ UNUSED(var); UNUSED(val_ptr);
+ #endif
+}
+
+void DGUSScreenHandler::HandleManualExtrude(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleManualExtrude");
+
+ int16_t movevalue = swap16(*(uint16_t*)val_ptr);
+ float target = movevalue * 0.01f;
+ ExtUI::extruder_t target_extruder;
+
+ switch (var.VP) {
+ #if HAS_HOTEND
+ case VP_MOVE_E0: target_extruder = ExtUI::extruder_t::E0; break;
+ #if HAS_MULTI_EXTRUDER
+ case VP_MOVE_E1: target_extruder = ExtUI::extruder_t::E1; break;
+ #endif
+ #endif
+ default: return;
+ }
+
+ target += ExtUI::getAxisPosition_mm(target_extruder);
+ ExtUI::setAxisPosition_mm(target, target_extruder);
+ skipVP = var.VP;
+}
+
+#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ void DGUSScreenHandler::HandleManualMoveOption(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleManualMoveOption");
+ *(uint16_t*)var.memadr = swap16(*(uint16_t*)val_ptr);
+ }
+#endif
+
+void DGUSScreenHandler::HandleMotorLockUnlock(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleMotorLockUnlock");
+ const int16_t lock = swap16(*(uint16_t*)val_ptr);
+ queue.enqueue_one_now(lock ? F("M18") : F("M17"));
+}
+
+void DGUSScreenHandler::HandleSettings(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleSettings");
+ uint16_t value = swap16(*(uint16_t*)val_ptr);
+ switch (value) {
+ default: break;
+ case 1:
+ TERN_(PRINTCOUNTER, print_job_timer.initStats());
+ settings.reset();
+ settings.save();
+ break;
+ case 2: settings.load(); break;
+ case 3: settings.save(); break;
+ }
+}
+
+void DGUSScreenHandler::HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleStepPerMMChanged");
+
+ uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("value_raw:", value_raw);
+ float value = (float)value_raw / 10;
+ ExtUI::axis_t axis;
+ switch (var.VP) {
+ case VP_X_STEP_PER_MM: axis = ExtUI::axis_t::X; break;
+ case VP_Y_STEP_PER_MM: axis = ExtUI::axis_t::Y; break;
+ case VP_Z_STEP_PER_MM: axis = ExtUI::axis_t::Z; break;
+ default: return;
+ }
+ DEBUG_ECHOLNPGM("value:", value);
+ ExtUI::setAxisSteps_per_mm(value, axis);
+ DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisSteps_per_mm(axis));
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ return;
+}
+
+void DGUSScreenHandler::HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleStepPerMMExtruderChanged");
+
+ uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("value_raw:", value_raw);
+ float value = (float)value_raw / 10;
+ ExtUI::extruder_t extruder;
+ switch (var.VP) {
+ default: return;
+ #if HAS_EXTRUDERS
+ case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break;
+ #if HAS_MULTI_EXTRUDER
+ case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break;
+ #endif
+ #endif
+ }
+ DEBUG_ECHOLNPGM("value:", value);
+ ExtUI::setAxisSteps_per_mm(value, extruder);
+ DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisSteps_per_mm(extruder));
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+#if HAS_PID_HEATING
+ void DGUSScreenHandler::HandlePIDAutotune(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandlePIDAutotune");
+
+ char buf[32] = {0};
+
+ switch (var.VP) {
+ default: break;
+ #if ENABLED(PIDTEMP)
+ #if HAS_HOTEND
+ case VP_PID_AUTOTUNE_E0: // Autotune Extruder 0
+ sprintf_P(buf, PSTR("M303 E%d C5 S210 U1"), ExtUI::extruder_t::E0);
+ queue.enqueue_one_now(buf);
+ break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_PID_AUTOTUNE_E1:
+ sprintf_P(buf, PSTR("M303 E%d C5 S210 U1"), ExtUI::extruder_t::E1);
+ queue.enqueue_one_now(buf);
+ break;
+ #endif
+ #endif
+ #if ENABLED(PIDTEMPBED)
+ case VP_PID_AUTOTUNE_BED:
+ queue.enqueue_one_now(F("M303 E-1 C5 S70 U1"));
+ break;
+ #endif
+ }
+
+ #if ENABLED(DGUS_UI_WAITING)
+ sendinfoscreen(F("PID is autotuning"), F("please wait"), NUL_STR, NUL_STR, true, true, true, true);
+ GotoScreen(DGUSLCD_SCREEN_WAITING);
+ #endif
+ }
+#endif // HAS_PID_HEATING
+
+#if HAS_BED_PROBE
+ void DGUSScreenHandler::HandleProbeOffsetZChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleProbeOffsetZChanged");
+
+ const float offset = float(int16_t(swap16(*(uint16_t*)val_ptr))) / 100.0f;
+ ExtUI::setZOffset_mm(offset);
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ return;
+ }
+#endif
+
+#if HAS_FAN
+ void DGUSScreenHandler::HandleFanControl(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleFanControl");
+ *(uint8_t*)var.memadr = *(uint8_t*)var.memadr > 0 ? 0 : 255;
+ }
+#endif
+
+void DGUSScreenHandler::HandleHeaterControl(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleHeaterControl");
+
+ uint8_t preheat_temp = 0;
+ switch (var.VP) {
+ #if HAS_HOTEND
+ case VP_E0_CONTROL:
+ #if HAS_MULTI_HOTEND
+ case VP_E1_CONTROL:
+ #if HOTENDS >= 3
+ case VP_E2_CONTROL:
+ #endif
+ #endif
+ preheat_temp = PREHEAT_1_TEMP_HOTEND;
+ break;
+ #endif
+
+ #if HAS_HEATED_BED
+ case VP_BED_CONTROL:
+ preheat_temp = PREHEAT_1_TEMP_BED;
+ break;
+ #endif
+ }
+
+ *(int16_t*)var.memadr = *(int16_t*)var.memadr > 0 ? 0 : preheat_temp;
+}
+
+#if ENABLED(DGUS_PREHEAT_UI)
+
+ void DGUSScreenHandler::HandlePreheat(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandlePreheat");
+
+ const uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
+ switch (preheat_option) {
+ default:
+ switch (var.VP) {
+ default: return;
+ case VP_E0_BED_PREHEAT: TERN_(HAS_HOTEND, ui.preheat_all(0)); break;
+ #if DISABLED(DGUS_LCD_UI_HIPRECY) && HAS_MULTI_HOTEND
+ case VP_E1_BED_PREHEAT: ui.preheat_all(1); break;
+ #endif
+ }
+ case 7: break; // Custom preheat
+ case 9: thermalManager.cooldown(); break; // Cool down
+ }
+
+ // Go to the preheat screen to show the heating progress
+ GotoScreen(DGUSLCD_SCREEN_PREHEAT);
+ }
+
+#endif // DGUS_PREHEAT_UI
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+
+ void DGUSScreenHandler::HandlePowerLossRecovery(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t value = swap16(*(uint16_t*)val_ptr);
+ if (value) {
+ queue.inject(F("M1000"));
+ dgusdisplay.WriteVariable(VP_SD_Print_Filename, filelist.filename(), 32, true);
+ GotoScreen(PLR_SCREEN_RECOVER);
+ }
+ else {
+ recovery.cancel();
+ GotoScreen(PLR_SCREEN_CANCEL);
+ }
+ }
+
+#endif
+
+void DGUSScreenHandler::UpdateNewScreen(DGUSLCD_Screens newscreen, bool popup) {
+ DEBUG_ECHOLNPGM("SetNewScreen: ", newscreen);
+ if (!popup) {
+ memmove(&past_screens[1], &past_screens[0], sizeof(past_screens) - 1);
+ past_screens[0] = current_screen;
+ }
+ current_screen = newscreen;
+ skipVP = 0;
+ ForceCompleteUpdate();
+}
+
+void DGUSScreenHandler::PopToOldScreen() {
+ DEBUG_ECHOLNPGM("PopToOldScreen s=", past_screens[0]);
+ GotoScreen(past_screens[0], true);
+ memmove(&past_screens[0], &past_screens[1], sizeof(past_screens) - 1);
+ past_screens[sizeof(past_screens) - 1] = DGUSLCD_SCREEN_MAIN;
+}
+
+void DGUSScreenHandler::UpdateScreenVPData() {
+ DEBUG_ECHOPGM(" UpdateScreenVPData Screen: ", current_screen);
+
+ const uint16_t *VPList = DGUSLCD_FindScreenVPMapList(current_screen);
+ if (!VPList) {
+ DEBUG_ECHOLNPGM(" NO SCREEN FOR: ", current_screen);
+ ScreenComplete = true;
+ return; // nothing to do, likely a bug or boring screen.
+ }
+
+ // Round-robin updating of all VPs.
+ VPList += update_ptr;
+
+ bool sent_one = false;
+ do {
+ uint16_t VP = pgm_read_word(VPList);
+ DEBUG_ECHOPGM(" VP: ", VP);
+ if (!VP) {
+ update_ptr = 0;
+ DEBUG_ECHOLNPGM(" UpdateScreenVPData done");
+ ScreenComplete = true;
+ return; // Screen completed.
+ }
+
+ if (VP == skipVP) { skipVP = 0; continue; }
+
+ DGUS_VP_Variable rcpy;
+ if (populate_VPVar(VP, &rcpy)) {
+ uint8_t expected_tx = 6 + rcpy.size; // expected overhead is 6 bytes + payload.
+ // Send the VP to the display, but try to avoid overrunning the Tx Buffer.
+ // But send at least one VP, to avoid getting stalled.
+ if (rcpy.send_to_display_handler && (!sent_one || expected_tx <= dgusdisplay.GetFreeTxBuffer())) {
+ //DEBUG_ECHOPGM(" calling handler for ", rcpy.VP);
+ sent_one = true;
+ rcpy.send_to_display_handler(rcpy);
+ }
+ else {
+ // auto x=dgusdisplay.GetFreeTxBuffer();
+ //DEBUG_ECHOLNPGM(" tx almost full: ", x);
+ //DEBUG_ECHOPGM(" update_ptr ", update_ptr);
+ ScreenComplete = false;
+ return; // please call again!
+ }
+ }
+
+ } while (++update_ptr, ++VPList, true);
+}
+
+void DGUSScreenHandler::GotoScreen(DGUSLCD_Screens screen, bool ispopup) {
+ dgusdisplay.RequestScreen(screen);
+ UpdateNewScreen(screen, ispopup);
+}
+
+void DGUSDisplay::RequestScreen(DGUSLCD_Screens screen) {
+ DEBUG_ECHOLNPGM("GotoScreen ", screen);
+ const unsigned char gotoscreen[] = { 0x5A, 0x01, (unsigned char) (screen >> 8U), (unsigned char) (screen & 0xFFU) };
+ WriteVariable(0x84, gotoscreen, sizeof(gotoscreen));
+}
+
+#endif // HAS_DGUS_LCD_CLASSIC
diff --git a/src/lcd/extui/dgus/DGUSScreenHandler.h b/src/lcd/extui/dgus/DGUSScreenHandler.h
new file mode 100644
index 0000000..4b627fe
--- /dev/null
+++ b/src/lcd/extui/dgus/DGUSScreenHandler.h
@@ -0,0 +1,73 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+/**
+ * lcd/extui/dgus/DGUSScreenHandler.h
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#include "../ui_api.h"
+
+#if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+
+ typedef struct {
+ ExtUI::extruder_t extruder; // which extruder to operate
+ uint8_t action; // load or unload
+ bool heated; // heating done ?
+ float purge_length; // the length to extrude before unload, prevent filament jam
+ } filament_data_t;
+
+ extern filament_data_t filament_data;
+
+#endif
+
+#if ENABLED(DGUS_LCD_UI_ORIGIN)
+ #include "origin/DGUSScreenHandler.h"
+#elif ENABLED(DGUS_LCD_UI_MKS)
+ #include "mks/DGUSScreenHandler.h"
+#elif ENABLED(DGUS_LCD_UI_FYSETC)
+ #include "fysetc/DGUSScreenHandler.h"
+#elif ENABLED(DGUS_LCD_UI_HIPRECY)
+ #include "hiprecy/DGUSScreenHandler.h"
+#endif
+
+extern DGUSScreenHandlerClass ScreenHandler;
+
+// Helper to define a DGUS_VP_Variable for common use-cases.
+#define VPHELPER(VPADR, VPADRVAR, RXFPTR, TXFPTR) { \
+ .VP = VPADR, \
+ .memadr = VPADRVAR, \
+ .size = sizeof(VPADRVAR), \
+ .set_by_display_handler = RXFPTR, \
+ .send_to_display_handler = TXFPTR \
+}
+
+// Helper to define a DGUS_VP_Variable when the size of the var cannot be determined automatically (e.g., a string)
+#define VPHELPER_STR(VPADR, VPADRVAR, STRLEN, RXFPTR, TXFPTR) { \
+ .VP = VPADR, \
+ .memadr = VPADRVAR, \
+ .size = STRLEN, \
+ .set_by_display_handler = RXFPTR, \
+ .send_to_display_handler = TXFPTR \
+}
diff --git a/src/lcd/extui/dgus/DGUSScreenHandlerBase.h b/src/lcd/extui/dgus/DGUSScreenHandlerBase.h
new file mode 100644
index 0000000..07a108e
--- /dev/null
+++ b/src/lcd/extui/dgus/DGUSScreenHandlerBase.h
@@ -0,0 +1,241 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2022 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 .
+ *
+ */
+#pragma once
+
+#include "DGUSDisplay.h"
+#include "DGUSVPVariable.h"
+#include "DGUSDisplayDef.h"
+
+#include "../../../inc/MarlinConfig.h"
+
+enum DGUSLCD_Screens : uint8_t;
+
+class DGUSScreenHandler {
+public:
+ DGUSScreenHandler() = default;
+
+ static bool loop();
+
+ // Send all 4 strings that are displayed on the infoscreen, confirmation screen and kill screen
+ // The bools specifying whether the strings are in RAM or FLASH.
+ static void sendinfoscreen(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash);
+ static void sendinfoscreen(FSTR_P const line1, FSTR_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash) {
+ sendinfoscreen(FTOP(line1), FTOP(line2), line3, line4, l1inflash, l2inflash, l3inflash, liinflash);
+ }
+ static void sendinfoscreen(FSTR_P const line1, FSTR_P const line2, FSTR_P const line3, FSTR_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash) {
+ sendinfoscreen(FTOP(line1), FTOP(line2), FTOP(line3), FTOP(line4), l1inflash, l2inflash, l3inflash, liinflash);
+ }
+
+ static void HandleUserConfirmationPopUp(uint16_t ConfirmVP, PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash);
+
+ // "M117" Message -- msg is a RAM ptr.
+ static void setstatusmessage(const char *msg);
+ // The same for messages from Flash
+ static void setstatusmessagePGM(PGM_P const msg);
+ // Callback for VP "Display wants to change screen on idle printer"
+ static void ScreenChangeHookIfIdle(DGUS_VP_Variable &var, void *val_ptr);
+ // Callback for VP "Screen has been changed"
+ static void ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr);
+
+ // Callback for VP "All Heaters Off"
+ static void HandleAllHeatersOff(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for "Change this temperature"
+ static void HandleTemperatureChanged(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for "Change Flowrate"
+ static void HandleFlowRateChanged(DGUS_VP_Variable &var, void *val_ptr);
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ // Hook for manual move option
+ static void HandleManualMoveOption(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+
+ // Hook for manual move.
+ static void HandleManualMove(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for manual extrude.
+ static void HandleManualExtrude(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for motor lock and unlook
+ static void HandleMotorLockUnlock(DGUS_VP_Variable &var, void *val_ptr);
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ // Hook for power loss recovery.
+ static void HandlePowerLossRecovery(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ // Hook for settings
+ static void HandleSettings(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr);
+
+ #if HAS_PID_HEATING
+ // Hook for "Change this temperature PID para"
+ static void HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for PID autotune
+ static void HandlePIDAutotune(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ #if HAS_BED_PROBE
+ // Hook for "Change probe offset z"
+ static void HandleProbeOffsetZChanged(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ #if ENABLED(BABYSTEPPING)
+ // Hook for live z adjust action
+ static void HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ #if HAS_FAN
+ // Hook for fan control
+ static void HandleFanControl(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ // Hook for heater control
+ static void HandleHeaterControl(DGUS_VP_Variable &var, void *val_ptr);
+ #if ENABLED(DGUS_PREHEAT_UI)
+ // Hook for preheat
+ static void HandlePreheat(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ // Hook for filament load and unload filament option
+ static void HandleFilamentOption(DGUS_VP_Variable &var, void *val_ptr);
+ // Hook for filament load and unload
+ static void HandleFilamentLoadUnload(DGUS_VP_Variable &var);
+ #endif
+
+ #if ENABLED(SDSUPPORT)
+ // Callback for VP "Display wants to change screen when there is a SD card"
+ static void ScreenChangeHookIfSD(DGUS_VP_Variable &var, void *val_ptr);
+ // Scroll buttons on the file listing screen.
+ static void DGUSLCD_SD_ScrollFilelist(DGUS_VP_Variable &var, void *val_ptr);
+ // File touched.
+ static void DGUSLCD_SD_FileSelected(DGUS_VP_Variable &var, void *val_ptr);
+ // start print after confirmation received.
+ static void DGUSLCD_SD_StartPrint(DGUS_VP_Variable &var, void *val_ptr);
+ // User hit the pause, resume or abort button.
+ static void DGUSLCD_SD_ResumePauseAbort(DGUS_VP_Variable &var, void *val_ptr);
+ // User confirmed the abort action
+ static void DGUSLCD_SD_ReallyAbort(DGUS_VP_Variable &var, void *val_ptr);
+ // User hit the tune button
+ static void DGUSLCD_SD_PrintTune(DGUS_VP_Variable &var, void *val_ptr);
+ // Send a single filename to the display.
+ static void DGUSLCD_SD_SendFilename(DGUS_VP_Variable &var);
+ // Marlin informed us that a new SD has been inserted.
+ static void SDCardInserted();
+ // Marlin informed us that the SD Card has been removed().
+ static void SDCardRemoved();
+ // Marlin informed us about a bad SD Card.
+ static void SDCardError();
+ #endif
+
+ // OK Button on the Confirm screen.
+ static void ScreenConfirmedOK(DGUS_VP_Variable &var, void *val_ptr);
+
+ // Update data after going to a new screen (by display or by GotoScreen)
+ // remember to store the last-displayed screen so it can be restored.
+ // (e.g., for popup messages)
+ static void UpdateNewScreen(DGUSLCD_Screens newscreen, bool popup=false);
+
+ // Recall the remembered screen.
+ static void PopToOldScreen();
+
+ // Make the display show the screen and update all VPs in it.
+ static void GotoScreen(DGUSLCD_Screens screen, bool ispopup = false);
+
+ static void UpdateScreenVPData();
+
+ // Helpers to convert and transfer data to the display.
+ static void DGUSLCD_SendWordValueToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendStringToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendStringToDisplayPGM(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendTemperaturePID(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendPercentageToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendPrintProgressToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var);
+
+ #if ENABLED(PRINTCOUNTER)
+ static void DGUSLCD_SendPrintAccTimeToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendPrintsTotalToDisplay(DGUS_VP_Variable &var);
+ #endif
+ #if HAS_FAN
+ static void DGUSLCD_SendFanStatusToDisplay(DGUS_VP_Variable &var);
+ #endif
+ static void DGUSLCD_SendHeaterStatusToDisplay(DGUS_VP_Variable &var);
+ #if ENABLED(DGUS_UI_WAITING)
+ static void DGUSLCD_SendWaitingStatusToDisplay(DGUS_VP_Variable &var);
+ #endif
+
+ // Send a value from 0..100 to a variable with a range from 0..255
+ static void DGUSLCD_PercentageToUint8(DGUS_VP_Variable &var, void *val_ptr);
+
+ template
+ static void DGUSLCD_SetValueDirectly(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!var.memadr) return;
+ union { unsigned char tmp[sizeof(T)]; T t; } x;
+ unsigned char *ptr = (unsigned char*)val_ptr;
+ LOOP_L_N(i, sizeof(T)) x.tmp[i] = ptr[sizeof(T) - i - 1];
+ *(T*)var.memadr = x.t;
+ }
+
+ // Send a float value to the display.
+ // Display will get a 4-byte integer scaled to the number of digits:
+ // Tell the display the number of digits and it cheats by displaying a dot between...
+ template
+ static void DGUSLCD_SendFloatAsLongValueToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ float f = *(float *)var.memadr;
+ f *= cpow(10, decimals);
+ dgusdisplay.WriteVariable(var.VP, (long)f);
+ }
+ }
+
+ // Send a float value to the display.
+ // Display will get a 2-byte integer scaled to the number of digits:
+ // Tell the display the number of digits and it cheats by displaying a dot between...
+ template
+ static void DGUSLCD_SendFloatAsIntValueToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ float f = *(float *)var.memadr;
+ DEBUG_ECHOLNPAIR_F(" >> ", f, 6);
+ f *= cpow(10, decimals);
+ dgusdisplay.WriteVariable(var.VP, (int16_t)f);
+ }
+ }
+
+ // Force an update of all VP on the current screen.
+ static void ForceCompleteUpdate() { update_ptr = 0; ScreenComplete = false; }
+ // Has all VPs sent to the screen
+ static bool IsScreenComplete() { return ScreenComplete; }
+
+ static DGUSLCD_Screens getCurrentScreen() { return current_screen; }
+
+ static void SetupConfirmAction( void (*f)()) { confirm_action_cb = f; }
+
+protected:
+ static DGUSLCD_Screens current_screen; //< currently on screen
+ static constexpr uint8_t NUM_PAST_SCREENS = 4;
+ static DGUSLCD_Screens past_screens[NUM_PAST_SCREENS]; //< LIFO with past screens for the "back" button.
+
+ static uint8_t update_ptr; //< Last sent entry in the VPList for the actual screen.
+ static uint16_t skipVP; //< When updating the screen data, skip this one, because the user is interacting with it.
+ static bool ScreenComplete; //< All VPs sent to screen?
+
+ static uint16_t ConfirmVP; //< context for confirm screen (VP that will be emulated-sent on "OK").
+
+ #if ENABLED(SDSUPPORT)
+ static int16_t top_file; //< file on top of file chooser
+ static int16_t file_to_print; //< touched file to be confirmed
+ #endif
+
+ static void (*confirm_action_cb)();
+};
diff --git a/src/lcd/extui/dgus/DGUSVPVariable.h b/src/lcd/extui/dgus/DGUSVPVariable.h
new file mode 100644
index 0000000..8c193c7
--- /dev/null
+++ b/src/lcd/extui/dgus/DGUSVPVariable.h
@@ -0,0 +1,49 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+#include
+
+/**
+ * DGUSVPVariable.h
+ *
+ * Created on: Feb 9, 2019
+ * Author: tobi
+ */
+
+struct DGUS_VP_Variable {
+ uint16_t VP;
+ void* memadr; // If nullptr, the value cannot be uploaded to the display.
+ uint8_t size;
+
+ // Callback that will be called if the display modified the value.
+ // nullptr makes it readonly for the display.
+ void (*set_by_display_handler)(DGUS_VP_Variable &var, void *val_ptr);
+ void (*send_to_display_handler)(DGUS_VP_Variable &var);
+
+ template
+ DGUS_VP_Variable& operator =(T &o) {
+ *(T*)memadr = o; // warning this is not typesafe.
+ // TODO: Call out the display or mark as dirty for the next update.
+ return *this;
+ }
+};
diff --git a/src/lcd/extui/dgus/dgus_extui.cpp b/src/lcd/extui/dgus/dgus_extui.cpp
new file mode 100644
index 0000000..b041687
--- /dev/null
+++ b/src/lcd/extui/dgus/dgus_extui.cpp
@@ -0,0 +1,163 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/**
+ * lcd/extui/dgus/dgus_extui.cpp
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if HAS_DGUS_LCD_CLASSIC
+
+#include "../ui_api.h"
+#include "DGUSDisplay.h"
+#include "DGUSDisplayDef.h"
+#include "DGUSScreenHandler.h"
+
+namespace ExtUI {
+
+ void onStartup() {
+ dgusdisplay.InitDisplay();
+ ScreenHandler.UpdateScreenVPData();
+ }
+
+ void onIdle() { ScreenHandler.loop(); }
+
+ void onPrinterKilled(FSTR_P const error, FSTR_P const) {
+ ScreenHandler.sendinfoscreen(GET_TEXT_F(MSG_HALTED), error, FPSTR(NUL_STR), GET_TEXT_F(MSG_PLEASE_RESET), true, true, true, true);
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_KILL);
+ while (!ScreenHandler.loop()); // Wait while anything is left to be sent
+ }
+
+ void onMediaInserted() { TERN_(SDSUPPORT, ScreenHandler.SDCardInserted()); }
+ void onMediaError() { TERN_(SDSUPPORT, ScreenHandler.SDCardError()); }
+ void onMediaRemoved() { TERN_(SDSUPPORT, ScreenHandler.SDCardRemoved()); }
+
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {}
+ void onPrintTimerStarted() {}
+ void onPrintTimerPaused() {}
+ void onPrintTimerStopped() {}
+ void onFilamentRunout(const extruder_t extruder) {}
+
+ void onUserConfirmRequired(const char * const msg) {
+ if (msg) {
+ ScreenHandler.sendinfoscreen(F("Please confirm."), nullptr, msg, nullptr, true, true, false, true);
+ ScreenHandler.SetupConfirmAction(setUserConfirmed);
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_POPUP);
+ }
+ else if (ScreenHandler.getCurrentScreen() == DGUSLCD_SCREEN_POPUP) {
+ ScreenHandler.SetupConfirmAction(nullptr);
+ ScreenHandler.PopToOldScreen();
+ }
+ }
+
+ void onStatusChanged(const char * const msg) { ScreenHandler.setstatusmessage(msg); }
+
+ void onHomingStart() {}
+ void onHomingDone() {}
+ void onPrintDone() {}
+
+ void onFactoryReset() {}
+
+ void onStoreSettings(char *buff) {
+ // Called when saving to EEPROM (i.e. M500). If the ExtUI needs
+ // permanent data to be stored, it can write up to eeprom_data_size bytes
+ // into buff.
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= eeprom_data_size);
+ // memcpy(buff, &myDataStruct, sizeof(myDataStruct));
+ }
+
+ void onLoadSettings(const char *buff) {
+ // Called while loading settings from EEPROM. If the ExtUI
+ // needs to retrieve data, it should copy up to eeprom_data_size bytes
+ // from buff
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= eeprom_data_size);
+ // memcpy(&myDataStruct, buff, sizeof(myDataStruct));
+ }
+
+ void onPostprocessSettings() {
+ // Called after loading or resetting stored settings
+ }
+
+ void onSettingsStored(bool success) {
+ // Called after the entire EEPROM has been written,
+ // whether successful or not.
+ }
+
+ void onSettingsLoaded(bool success) {
+ // Called after the entire EEPROM has been read,
+ // whether successful or not.
+ }
+
+ #if HAS_MESH
+ void onLevelingStart() {}
+ void onLevelingDone() {}
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) {
+ // Called when any mesh points are updated
+ }
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const probe_state_t state) {
+ // Called to indicate a special condition
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {
+ // Called on resume from power-loss
+ IF_DISABLED(DGUS_LCD_UI_MKS, ScreenHandler.GotoScreen(DGUSLCD_SCREEN_POWER_LOSS));
+ }
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ switch (rst) {
+ case PID_STARTED:
+ ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_AUTOTUNE));
+ break;
+ case PID_BAD_EXTRUDER_NUM:
+ ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_BAD_EXTRUDER_NUM));
+ break;
+ case PID_TEMP_TOO_HIGH:
+ ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_TEMP_TOO_HIGH));
+ break;
+ case PID_TUNING_TIMEOUT:
+ ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_TIMEOUT));
+ break;
+ case PID_DONE:
+ ScreenHandler.setstatusmessagePGM(GET_TEXT(MSG_PID_AUTOTUNE_DONE));
+ break;
+ }
+ ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // HAS_DGUS_LCD_CLASSIC
diff --git a/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp b/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp
new file mode 100644
index 0000000..a4c0997
--- /dev/null
+++ b/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.cpp
@@ -0,0 +1,478 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/* DGUS VPs changed by George Fu in 2019 for Marlin */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_FYSETC)
+
+#include "DGUSDisplayDef.h"
+#include "../DGUSDisplay.h"
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+
+#include "../../ui_api.h"
+#include "../../../marlinui.h"
+
+#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ uint16_t distanceToMove = 10;
+#endif
+
+const uint16_t VPList_Boot[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ 0x0000
+};
+
+const uint16_t VPList_Main[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded.
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set, VP_E0_STATUS,
+ #endif
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set, VP_BED_STATUS,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage, VP_FAN0_STATUS,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ #if ENABLED(LCD_SET_PROGRESS_MANUALLY)
+ VP_PrintProgress_Percentage,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Temp[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Status[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ VP_PrintProgress_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_Status2[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded
+ #if HAS_HOTEND
+ VP_Flowrate_E0,
+ #if HAS_MULTI_EXTRUDER
+ VP_Flowrate_E1,
+ #endif
+ #endif
+ VP_PrintProgress_Percentage,
+ VP_PrintTime,
+ 0x0000
+};
+
+const uint16_t VPList_Preheat[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_ManualMove[] PROGMEM = {
+ VP_XPos, VP_YPos, VP_ZPos,
+ 0x0000
+};
+
+const uint16_t VPList_ManualExtrude[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #if HAS_MULTI_EXTRUDER
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ VP_EPos,
+ 0x0000
+};
+
+const uint16_t VPList_FanAndFeedrate[] PROGMEM = {
+ VP_Feedrate_Percentage, VP_Fan0_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_SD_FlowRates[] PROGMEM = {
+ VP_Flowrate_E0, VP_Flowrate_E1,
+ 0x0000
+};
+
+const uint16_t VPList_Filament_heating[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ VP_E0_FILAMENT_LOAD_UNLOAD,
+ #if HAS_MULTI_EXTRUDER
+ VP_T_E1_Is, VP_T_E1_Set,
+ VP_E1_FILAMENT_LOAD_UNLOAD,
+ #endif
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Filament_load_unload[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_E0_FILAMENT_LOAD_UNLOAD,
+ #if HAS_MULTI_EXTRUDER
+ VP_E1_FILAMENT_LOAD_UNLOAD,
+ #endif
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_SDFileList[] PROGMEM = {
+ VP_SD_FileName0, VP_SD_FileName1, VP_SD_FileName2, VP_SD_FileName3, VP_SD_FileName4,
+ 0x0000
+};
+
+const uint16_t VPList_SD_PrintManipulation[] PROGMEM = {
+ VP_PrintProgress_Percentage, VP_PrintTime,
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #if FAN_COUNT > 1
+ VP_Fan1_Percentage,
+ #endif
+ #endif
+ VP_Flowrate_E0,
+ 0x0000
+};
+
+const uint16_t VPList_SDPrintTune[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set, VP_Flowrate_E0,
+ #if HAS_MULTI_EXTRUDER
+ VP_T_E1_Is, VP_T_E1_Set, VP_Flowrate_E1, // ERROR: Flowrate is per-extruder, not per-hotend
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ VP_Feedrate_Percentage,
+ VP_SD_Print_ProbeOffsetZ,
+ 0x0000
+};
+
+const uint16_t VPList_StepPerMM[] PROGMEM = {
+ VP_X_STEP_PER_MM,
+ VP_Y_STEP_PER_MM,
+ VP_Z_STEP_PER_MM,
+ #if HAS_EXTRUDERS
+ VP_E0_STEP_PER_MM,
+ #if HAS_MULTI_EXTRUDER
+ VP_E1_STEP_PER_MM,
+ #endif
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDE0[] PROGMEM = {
+ #if ENABLED(PIDTEMP)
+ VP_E0_PID_P,
+ VP_E0_PID_I,
+ VP_E0_PID_D,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDBED[] PROGMEM = {
+ #if ENABLED(PIDTEMP)
+ VP_BED_PID_P,
+ VP_BED_PID_I,
+ VP_BED_PID_D,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Infos[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ VP_PrintTime,
+ #if ENABLED(PRINTCOUNTER)
+ VP_PrintAccTime,
+ VP_PrintsTotal,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDTuningWaiting[] PROGMEM = {
+ VP_WAITING_STATUS,
+ 0x0000
+};
+
+const uint16_t VPList_FLCPreheat[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_FLCPrinting[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_SD_Print_ProbeOffsetZ,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Z_Offset[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_SD_Print_ProbeOffsetZ,
+ #endif
+ 0x0000
+};
+
+const struct VPMapping VPMap[] PROGMEM = {
+ { DGUSLCD_SCREEN_BOOT, VPList_Boot },
+ { DGUSLCD_SCREEN_MAIN, VPList_Main },
+ { DGUSLCD_SCREEN_TEMPERATURE, VPList_Temp },
+ { DGUSLCD_SCREEN_STATUS, VPList_Status },
+ { DGUSLCD_SCREEN_STATUS2, VPList_Status2 },
+ { DGUSLCD_SCREEN_PREHEAT, VPList_Preheat },
+ { DGUSLCD_SCREEN_MANUALMOVE, VPList_ManualMove },
+ { DGUSLCD_SCREEN_MANUALEXTRUDE, VPList_ManualExtrude },
+ { DGUSLCD_SCREEN_FILAMENT_HEATING, VPList_Filament_heating },
+ { DGUSLCD_SCREEN_FILAMENT_LOADING, VPList_Filament_load_unload },
+ { DGUSLCD_SCREEN_FILAMENT_UNLOADING, VPList_Filament_load_unload },
+ { DGUSLCD_SCREEN_SDPRINTMANIPULATION, VPList_SD_PrintManipulation },
+ { DGUSLCD_SCREEN_SDFILELIST, VPList_SDFileList },
+ { DGUSLCD_SCREEN_SDPRINTTUNE, VPList_SDPrintTune },
+ { DGUSLCD_SCREEN_WAITING, VPList_PIDTuningWaiting },
+ { DGUSLCD_SCREEN_FLC_PREHEAT, VPList_FLCPreheat },
+ { DGUSLCD_SCREEN_FLC_PRINTING, VPList_FLCPrinting },
+ { DGUSLCD_SCREEN_Z_OFFSET, VPList_Z_Offset },
+ { DGUSLCD_SCREEN_STEPPERMM, VPList_StepPerMM },
+ { DGUSLCD_SCREEN_PID_E, VPList_PIDE0 },
+ { DGUSLCD_SCREEN_PID_BED, VPList_PIDBED },
+ { DGUSLCD_SCREEN_INFOS, VPList_Infos },
+ { 0 , nullptr } // List is terminated with an nullptr as table entry.
+};
+
+const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION;
+
+const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
+ // Helper to detect touch events
+ VPHELPER(VP_SCREENCHANGE, nullptr, ScreenHandler.ScreenChangeHook, nullptr),
+ VPHELPER(VP_SCREENCHANGE_ASK, nullptr, ScreenHandler.ScreenChangeHookIfIdle, nullptr),
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SCREENCHANGE_WHENSD, nullptr, ScreenHandler.ScreenChangeHookIfSD, nullptr),
+ #endif
+ VPHELPER(VP_CONFIRMED, nullptr, ScreenHandler.ScreenConfirmedOK, nullptr),
+
+ VPHELPER(VP_TEMP_ALL_OFF, nullptr, ScreenHandler.HandleAllHeatersOff, nullptr),
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_OPTION, &distanceToMove, ScreenHandler.HandleManualMoveOption, nullptr),
+ #endif
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_X, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ #else
+ VPHELPER(VP_MOVE_X, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ #endif
+ VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, ScreenHandler.HandleMotorLockUnlock, nullptr),
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, ScreenHandler.HandlePowerLossRecovery, nullptr),
+ #endif
+ VPHELPER(VP_SETTINGS, nullptr, ScreenHandler.HandleSettings, nullptr),
+ #if ENABLED(SINGLE_Z_CALIBRATION)
+ VPHELPER(VP_Z_CALIBRATE, nullptr, ScreenHandler.HandleZCalibration, nullptr),
+ #endif
+
+ #if ENABLED(FIRST_LAYER_CAL)
+ VPHELPER(VP_Z_FIRST_LAYER_CAL, nullptr, ScreenHandler.HandleFirstLayerCal, nullptr),
+ #endif
+
+ { .VP = VP_MARLIN_VERSION, .memadr = (void*)MarlinVersion, .size = VP_MARLIN_VERSION_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ // M117 LCD String (We don't need the string in memory but "just" push it to the display on demand, hence the nullptr
+ { .VP = VP_M117, .memadr = nullptr, .size = VP_M117_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplay },
+
+ // Temperature Data
+ #if HAS_HOTEND
+ VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[ExtUI::extruder_t::E0], ScreenHandler.HandleFlowRateChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_EPos, &destination.e, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_MOVE_E0, nullptr, ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E0_STATUS, &thermalManager.temp_hotend[0].target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(DGUS_PREHEAT_UI)
+ VPHELPER(VP_E0_BED_PREHEAT, nullptr, ScreenHandler.HandlePreheat, nullptr),
+ #endif
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_E0_PID_P, &thermalManager.temp_hotend[0].pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_I, &thermalManager.temp_hotend[0].pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_D, &thermalManager.temp_hotend[0].pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_E0, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ VPHELPER(VP_E0_FILAMENT_LOAD_UNLOAD, nullptr, ScreenHandler.HandleFilamentOption, ScreenHandler.HandleFilamentLoadUnload),
+ #endif
+ #endif
+ #if HAS_MULTI_HOTEND
+ VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E1, &planner.flow_percentage[ExtUI::extruder_t::E1], ScreenHandler.HandleFlowRateChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay), // ERROR: Flow is per-extruder, not per-hotend
+ VPHELPER(VP_MOVE_E1, nullptr, ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_PID_AUTOTUNE_E1, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ VPHELPER(VP_E1_FILAMENT_LOAD_UNLOAD, nullptr, ScreenHandler.HandleFilamentOption, ScreenHandler.HandleFilamentLoadUnload),
+ #endif
+ #if HAS_HEATED_BED
+ VPHELPER(VP_T_Bed_Is, &thermalManager.temp_bed.celsius, nullptr, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_T_Bed_Set, &thermalManager.temp_bed.target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_BED_CONTROL, &thermalManager.temp_bed.target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_BED_STATUS, &thermalManager.temp_bed.target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMPBED)
+ VPHELPER(VP_BED_PID_P, &thermalManager.temp_bed.pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_I, &thermalManager.temp_bed.pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_D, &thermalManager.temp_bed.pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_BED, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #endif
+
+ // Fan Data
+ #if HAS_FAN
+ #define FAN_VPHELPER(N) \
+ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], ScreenHandler.DGUSLCD_PercentageToUint8, ScreenHandler.DGUSLCD_SendPercentageToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], ScreenHandler.HandleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, ScreenHandler.DGUSLCD_SendFanStatusToDisplay),
+ REPEAT(FAN_COUNT, FAN_VPHELPER)
+ #endif
+
+ // Feedrate
+ VPHELPER(VP_Feedrate_Percentage, &feedrate_percentage, ScreenHandler.DGUSLCD_SetValueDirectly, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+
+ // Position Data
+ VPHELPER(VP_XPos, ¤t_position.x, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_YPos, ¤t_position.y, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_ZPos, ¤t_position.z, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+
+ // Print Progress
+ VPHELPER(VP_PrintProgress_Percentage, nullptr, nullptr, ScreenHandler.DGUSLCD_SendPrintProgressToDisplay),
+
+ // Print Time
+ VPHELPER_STR(VP_PrintTime, nullptr, VP_PrintTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeToDisplay),
+ #if ENABLED(PRINTCOUNTER)
+ VPHELPER_STR(VP_PrintAccTime, nullptr, VP_PrintAccTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintAccTimeToDisplay),
+ VPHELPER_STR(VP_PrintsTotal, nullptr, VP_PrintsTotal_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintsTotalToDisplay),
+ #endif
+
+ VPHELPER(VP_X_STEP_PER_MM, &planner.settings.axis_steps_per_mm[X_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Y_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Y_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Z_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Z_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #if HAS_EXTRUDERS
+ VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #if HAS_MULTI_EXTRUDER
+ VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #endif
+ #endif
+
+ // SDCard File listing.
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SD_ScrollEvent, nullptr, ScreenHandler.DGUSLCD_SD_ScrollFilelist, nullptr),
+ VPHELPER(VP_SD_FileSelected, nullptr, ScreenHandler.DGUSLCD_SD_FileSelected, nullptr),
+ VPHELPER(VP_SD_FileSelectConfirm, nullptr, ScreenHandler.DGUSLCD_SD_StartPrint, nullptr),
+ VPHELPER_STR(VP_SD_FileName0, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName1, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName2, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName3, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName4, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER(VP_SD_ResumePauseAbort, nullptr, ScreenHandler.DGUSLCD_SD_ResumePauseAbort, nullptr),
+ VPHELPER(VP_SD_AbortPrintConfirmed, nullptr, ScreenHandler.DGUSLCD_SD_ReallyAbort, nullptr),
+ VPHELPER(VP_SD_Print_Setting, nullptr, ScreenHandler.DGUSLCD_SD_PrintTune, nullptr),
+ #if HAS_BED_PROBE
+ VPHELPER(VP_SD_Print_ProbeOffsetZ, &probe.offset.z, ScreenHandler.HandleProbeOffsetZChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<2>),
+ #if ENABLED(BABYSTEPPING)
+ VPHELPER(VP_SD_Print_LiveAdjustZ, nullptr, ScreenHandler.HandleLiveAdjustZ, nullptr),
+ #endif
+ #endif
+ #endif
+
+ #if ENABLED(DGUS_UI_WAITING)
+ VPHELPER(VP_WAITING_STATUS, nullptr, nullptr, ScreenHandler.DGUSLCD_SendWaitingStatusToDisplay),
+ #endif
+
+ // Messages for the User, shared by the popup and the kill screen. They can't be autouploaded as we do not buffer content.
+ { .VP = VP_MSGSTR1, .memadr = nullptr, .size = VP_MSGSTR1_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR2, .memadr = nullptr, .size = VP_MSGSTR2_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR3, .memadr = nullptr, .size = VP_MSGSTR3_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR4, .memadr = nullptr, .size = VP_MSGSTR4_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+
+ VPHELPER(0, 0, 0, 0) // must be last entry.
+};
+
+#endif // DGUS_LCD_UI_FYSETC
diff --git a/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h b/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h
new file mode 100644
index 0000000..2543d20
--- /dev/null
+++ b/src/lcd/extui/dgus/fysetc/DGUSDisplayDef.h
@@ -0,0 +1,296 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+#include "../DGUSDisplayDef.h"
+
+enum DGUSLCD_Screens : uint8_t {
+ DGUSLCD_SCREEN_BOOT = 0,
+ DGUSLCD_SCREEN_MAIN = 1,
+ DGUSLCD_SCREEN_STATUS = 1,
+ DGUSLCD_SCREEN_STATUS2 = 1,
+ DGUSLCD_SCREEN_TEMPERATURE = 10,
+ DGUSLCD_SCREEN_PREHEAT = 18,
+ DGUSLCD_SCREEN_POWER_LOSS = 100,
+ DGUSLCD_SCREEN_MANUALMOVE = 192,
+ DGUSLCD_SCREEN_UTILITY = 120,
+ DGUSLCD_SCREEN_FILAMENT_HEATING = 146,
+ DGUSLCD_SCREEN_FILAMENT_LOADING = 148,
+ DGUSLCD_SCREEN_FILAMENT_UNLOADING = 158,
+ DGUSLCD_SCREEN_MANUALEXTRUDE = 160,
+ DGUSLCD_SCREEN_SDFILELIST = 71,
+ DGUSLCD_SCREEN_SDPRINTMANIPULATION = 73,
+ DGUSLCD_SCREEN_SDPRINTTUNE = 75,
+ DGUSLCD_SCREEN_FLC_PREHEAT = 94,
+ DGUSLCD_SCREEN_FLC_PRINTING = 96,
+ DGUSLCD_SCREEN_STEPPERMM = 212,
+ DGUSLCD_SCREEN_PID_E = 214,
+ DGUSLCD_SCREEN_PID_BED = 218,
+ DGUSLCD_SCREEN_Z_OFFSET = 222,
+ DGUSLCD_SCREEN_INFOS = 36,
+ DGUSLCD_SCREEN_CONFIRM = 240,
+ DGUSLCD_SCREEN_KILL = 250, ///< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version")
+ DGUSLCD_SCREEN_WAITING = 251,
+ DGUSLCD_SCREEN_POPUP = 252, ///< special target, popup screen will also return this code to say "return to previous screen"
+ DGUSLCD_SCREEN_UNUSED = 255
+};
+
+// Display Memory layout used (T5UID)
+// Except system variables this is arbitrary, just to organize stuff....
+
+// 0x0000 .. 0x0FFF -- System variables and reserved by the display
+// 0x1000 .. 0x1FFF -- Variables to never change location, regardless of UI Version
+// 0x2000 .. 0x2FFF -- Controls (VPs that will trigger some action)
+// 0x3000 .. 0x4FFF -- Marlin Data to be displayed
+// 0x5000 .. -- SPs (if we want to modify display elements, e.g change color or like) -- currently unused
+
+// As there is plenty of space (at least most displays have >8k RAM), we do not pack them too tight,
+// so that we can keep variables nicely together in the address space.
+
+// UI Version always on 0x1000...0x1002 so that the firmware can check this and bail out.
+constexpr uint16_t VP_UI_VERSION_MAJOR = 0x1000; // Major -- incremented when incompatible
+constexpr uint16_t VP_UI_VERSION_MINOR = 0x1001; // Minor -- incremented on new features, but compatible
+constexpr uint16_t VP_UI_VERSION_PATCH = 0x1002; // Patch -- fixed which do not change functionality.
+constexpr uint16_t VP_UI_FLAVOUR = 0x1010; // lets reserve 16 bytes here to determine if UI is suitable for this Marlin. tbd.
+
+// Storage space for the Killscreen messages. 0x1100 - 0x1200 . Reused for the popup.
+constexpr uint16_t VP_MSGSTR1 = 0x1100;
+constexpr uint8_t VP_MSGSTR1_LEN = 0x20; // might be more place for it...
+constexpr uint16_t VP_MSGSTR2 = 0x1140;
+constexpr uint8_t VP_MSGSTR2_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR3 = 0x1180;
+constexpr uint8_t VP_MSGSTR3_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR4 = 0x11C0;
+constexpr uint8_t VP_MSGSTR4_LEN = 0x20;
+
+// Screenchange request for screens that only make sense when printer is idle.
+// e.g movement is only allowed if printer is not printing.
+// Marlin must confirm by setting the screen manually.
+constexpr uint16_t VP_SCREENCHANGE_ASK = 0x2000;
+constexpr uint16_t VP_SCREENCHANGE = 0x2001; // Key-Return button to new menu pressed. Data contains target screen in low byte and info in high byte.
+constexpr uint16_t VP_TEMP_ALL_OFF = 0x2002; // Turn all heaters off. Value arbitrary ;)=
+constexpr uint16_t VP_SCREENCHANGE_WHENSD = 0x2003; // "Print" Button touched -- go only there if there is an SD Card.
+
+constexpr uint16_t VP_CONFIRMED = 0x2010; // OK on confirm screen.
+
+// Buttons on the SD-Card File listing.
+constexpr uint16_t VP_SD_ScrollEvent = 0x2020; // Data: 0 for "up a directory", numbers are the amount to scroll, e.g -1 one up, 1 one down
+constexpr uint16_t VP_SD_FileSelected = 0x2022; // Number of file field selected.
+constexpr uint16_t VP_SD_FileSelectConfirm = 0x2024; // (This is a virtual VP and emulated by the Confirm Screen when a file has been confirmed)
+
+constexpr uint16_t VP_SD_ResumePauseAbort = 0x2026; // Resume(Data=0), Pause(Data=1), Abort(Data=2) SD Card prints
+constexpr uint16_t VP_SD_AbortPrintConfirmed = 0x2028; // Abort print confirmation (virtual, will be injected by the confirm dialog)
+constexpr uint16_t VP_SD_Print_Setting = 0x2040;
+constexpr uint16_t VP_SD_Print_LiveAdjustZ = 0x2050; // Data: 0 down, 1 up
+
+// Controls for movement (we can't use the incremental / decremental feature of the display at this feature works only with 16 bit values
+// (which would limit us to 655.35mm, which is likely not a problem for common setups, but i don't want to rule out hangprinters support)
+// A word about the coding: The VP will be per axis and the return code will be an signed 16 bit value in 0.01 mm resolution, telling us
+// the relative travel amount t he user wants to do. So eg. if the display sends us VP=2100 with value 100, the user wants us to move X by +1 mm.
+constexpr uint16_t VP_MOVE_X = 0x2100;
+constexpr uint16_t VP_MOVE_Y = 0x2102;
+constexpr uint16_t VP_MOVE_Z = 0x2104;
+constexpr uint16_t VP_MOVE_E0 = 0x2110;
+constexpr uint16_t VP_MOVE_E1 = 0x2112;
+//constexpr uint16_t VP_MOVE_E2 = 0x2114;
+//constexpr uint16_t VP_MOVE_E3 = 0x2116;
+//constexpr uint16_t VP_MOVE_E4 = 0x2118;
+//constexpr uint16_t VP_MOVE_E5 = 0x211A;
+constexpr uint16_t VP_HOME_ALL = 0x2120;
+constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130;
+
+// Power loss recovery
+constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180;
+
+// Fan Control Buttons , switch between "off" and "on"
+constexpr uint16_t VP_FAN0_CONTROL = 0x2200;
+constexpr uint16_t VP_FAN1_CONTROL = 0x2202;
+constexpr uint16_t VP_FAN2_CONTROL = 0x2204;
+constexpr uint16_t VP_FAN3_CONTROL = 0x2206;
+
+// Heater Control Buttons , triged between "cool down" and "heat PLA" state
+constexpr uint16_t VP_E0_CONTROL = 0x2210;
+constexpr uint16_t VP_E1_CONTROL = 0x2212;
+//constexpr uint16_t VP_E2_CONTROL = 0x2214;
+//constexpr uint16_t VP_E3_CONTROL = 0x2216;
+//constexpr uint16_t VP_E4_CONTROL = 0x2218;
+//constexpr uint16_t VP_E5_CONTROL = 0x221A;
+constexpr uint16_t VP_BED_CONTROL = 0x221C;
+
+// Preheat
+constexpr uint16_t VP_E0_BED_PREHEAT = 0x2220;
+constexpr uint16_t VP_E1_BED_PREHEAT = 0x2222;
+//constexpr uint16_t VP_E2_BED_PREHEAT = 0x2224;
+//constexpr uint16_t VP_E3_BED_PREHEAT = 0x2226;
+//constexpr uint16_t VP_E4_BED_PREHEAT = 0x2228;
+//constexpr uint16_t VP_E5_BED_PREHEAT = 0x222A;
+
+// Filament load and unload
+constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300;
+constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x2302;
+
+// Settings store , reset
+constexpr uint16_t VP_SETTINGS = 0x2400;
+
+// PID autotune
+constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x2410;
+constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x2412;
+//constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x2414;
+//constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x2416;
+//constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x2418;
+//constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x241A;
+constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x2420;
+
+// Calibrate Z
+constexpr uint16_t VP_Z_CALIBRATE = 0x2430;
+
+// First layer cal
+constexpr uint16_t VP_Z_FIRST_LAYER_CAL = 0x2500; // Data: 0 - Cancel first layer cal progress, >0 filament type have loaded
+
+// Firmware version on the boot screen.
+constexpr uint16_t VP_MARLIN_VERSION = 0x3000;
+constexpr uint8_t VP_MARLIN_VERSION_LEN = 16; // there is more space on the display, if needed.
+
+// Place for status messages.
+constexpr uint16_t VP_M117 = 0x3020;
+constexpr uint8_t VP_M117_LEN = 0x20;
+
+// Temperatures.
+constexpr uint16_t VP_T_E0_Is = 0x3060; // 4 Byte Integer
+constexpr uint16_t VP_T_E0_Set = 0x3062; // 2 Byte Integer
+constexpr uint16_t VP_T_E1_Is = 0x3064; // 4 Byte Integer
+
+// reserved to support up to 6 Extruders:
+constexpr uint16_t VP_T_E1_Set = 0x3066; // 2 Byte Integer
+//constexpr uint16_t VP_T_E2_Is = 0x3068; // 4 Byte Integer
+//constexpr uint16_t VP_T_E2_Set = 0x306A; // 2 Byte Integer
+//constexpr uint16_t VP_T_E3_Is = 0x306C; // 4 Byte Integer
+//constexpr uint16_t VP_T_E3_Set = 0x306E; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3070; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3072; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3074; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3076; // 2 Byte Integer
+//constexpr uint16_t VP_T_E5_Is = 0x3078; // 4 Byte Integer
+//constexpr uint16_t VP_T_E5_Set = 0x307A; // 2 Byte Integer
+
+constexpr uint16_t VP_T_Bed_Is = 0x3080; // 4 Byte Integer
+constexpr uint16_t VP_T_Bed_Set = 0x3082; // 2 Byte Integer
+
+constexpr uint16_t VP_Flowrate_E0 = 0x3090; // 2 Byte Integer
+constexpr uint16_t VP_Flowrate_E1 = 0x3092; // 2 Byte Integer
+
+// reserved for up to 6 Extruders:
+//constexpr uint16_t VP_Flowrate_E2 = 0x3094;
+//constexpr uint16_t VP_Flowrate_E3 = 0x3096;
+//constexpr uint16_t VP_Flowrate_E4 = 0x3098;
+//constexpr uint16_t VP_Flowrate_E5 = 0x309A;
+
+constexpr uint16_t VP_Fan0_Percentage = 0x3100; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan1_Percentage = 0x3102; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan2_Percentage = 0x3104; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan3_Percentage = 0x3106; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Feedrate_Percentage = 0x3108; // 2 Byte Integer (0..100)
+
+// Actual Position
+constexpr uint16_t VP_XPos = 0x3110; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_YPos = 0x3112; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_ZPos = 0x3114; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_EPos = 0x3120; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_PrintProgress_Percentage = 0x3130; // 2 Byte Integer (0..100)
+
+constexpr uint16_t VP_PrintTime = 0x3140;
+constexpr uint16_t VP_PrintTime_LEN = 32;
+
+constexpr uint16_t VP_PrintAccTime = 0x3160;
+constexpr uint16_t VP_PrintAccTime_LEN = 32;
+
+constexpr uint16_t VP_PrintsTotal = 0x3180;
+constexpr uint16_t VP_PrintsTotal_LEN = 16;
+
+// SDCard File Listing
+constexpr uint16_t VP_SD_FileName_LEN = 32; // LEN is shared for all entries.
+constexpr uint16_t DGUS_SD_FILESPERSCREEN = 5; // FIXME move that info to the display and read it from there.
+constexpr uint16_t VP_SD_FileName0 = 0x3200;
+constexpr uint16_t VP_SD_FileName1 = 0x3220;
+constexpr uint16_t VP_SD_FileName2 = 0x3240;
+constexpr uint16_t VP_SD_FileName3 = 0x3260;
+constexpr uint16_t VP_SD_FileName4 = 0x3280;
+
+constexpr uint16_t VP_SD_Print_ProbeOffsetZ = 0x32A0; //
+constexpr uint16_t VP_SD_Print_Filename = 0x32C0;
+
+// Fan status
+constexpr uint16_t VP_FAN0_STATUS = 0x3300;
+constexpr uint16_t VP_FAN1_STATUS = 0x3302;
+constexpr uint16_t VP_FAN2_STATUS = 0x3304;
+constexpr uint16_t VP_FAN3_STATUS = 0x3306;
+
+// Heater status
+constexpr uint16_t VP_E0_STATUS = 0x3310;
+constexpr uint16_t VP_E1_STATUS = 0x3312;
+//constexpr uint16_t VP_E2_STATUS = 0x3314;
+//constexpr uint16_t VP_E3_STATUS = 0x3316;
+//constexpr uint16_t VP_E4_STATUS = 0x3318;
+//constexpr uint16_t VP_E5_STATUS = 0x331A;
+constexpr uint16_t VP_BED_STATUS = 0x331C;
+
+constexpr uint16_t VP_MOVE_OPTION = 0x3400;
+
+// Step per mm
+constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment , 2 byte unsigned int , 0~1638.4
+//constexpr uint16_t VP_X2_STEP_PER_MM = 0x3602;
+constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604;
+//constexpr uint16_t VP_Y2_STEP_PER_MM = 0x3606;
+constexpr uint16_t VP_Z_STEP_PER_MM = 0x3608;
+//constexpr uint16_t VP_Z2_STEP_PER_MM = 0x360A;
+constexpr uint16_t VP_E0_STEP_PER_MM = 0x3610;
+constexpr uint16_t VP_E1_STEP_PER_MM = 0x3612;
+//constexpr uint16_t VP_E2_STEP_PER_MM = 0x3614;
+//constexpr uint16_t VP_E3_STEP_PER_MM = 0x3616;
+//constexpr uint16_t VP_E4_STEP_PER_MM = 0x3618;
+//constexpr uint16_t VP_E5_STEP_PER_MM = 0x361A;
+
+// PIDs
+constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , 2 byte unsigned int , 0~1638.4
+constexpr uint16_t VP_E0_PID_I = 0x3702;
+constexpr uint16_t VP_E0_PID_D = 0x3704;
+constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment , 2 byte unsigned int , 0~1638.4
+constexpr uint16_t VP_E1_PID_I = 0x3708;
+constexpr uint16_t VP_E1_PID_D = 0x370A;
+constexpr uint16_t VP_BED_PID_P = 0x3710;
+constexpr uint16_t VP_BED_PID_I = 0x3712;
+constexpr uint16_t VP_BED_PID_D = 0x3714;
+
+// Waiting screen status
+constexpr uint16_t VP_WAITING_STATUS = 0x3800;
+
+// SPs for certain variables...
+// located at 0x5000 and up
+// Not used yet!
+// This can be used e.g to make controls / data display invisible
+constexpr uint16_t SP_T_E0_Is = 0x5000;
+constexpr uint16_t SP_T_E0_Set = 0x5010;
+constexpr uint16_t SP_T_E1_Is = 0x5020;
+constexpr uint16_t SP_T_Bed_Is = 0x5030;
+constexpr uint16_t SP_T_Bed_Set = 0x5040;
diff --git a/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.cpp b/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.cpp
new file mode 100644
index 0000000..1f72c68
--- /dev/null
+++ b/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.cpp
@@ -0,0 +1,423 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_FYSETC)
+
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../MarlinCore.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../libs/duration_t.h"
+#include "../../../../module/settings.h"
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+#include "../../../../module/printcounter.h"
+#include "../../../../sd/cardreader.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if ENABLED(SDSUPPORT)
+
+ extern ExtUI::FileList filelist;
+
+ void DGUSScreenHandler::DGUSLCD_SD_FileSelected(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t touched_nr = (int16_t)swap16(*(uint16_t*)val_ptr) + top_file;
+ if (touched_nr > filelist.count()) return;
+ if (!filelist.seek(touched_nr)) return;
+
+ if (filelist.isDir()) {
+ filelist.changeDir(filelist.filename());
+ top_file = 0;
+ ForceCompleteUpdate();
+ return;
+ }
+
+ #if ENABLED(DGUS_PRINT_FILENAME)
+ // Send print filename
+ dgusdisplay.WriteVariable(VP_SD_Print_Filename, filelist.filename(), VP_SD_FileName_LEN, true);
+ #endif
+
+ // Setup Confirmation screen
+ file_to_print = touched_nr;
+
+ HandleUserConfirmationPopUp(VP_SD_FileSelectConfirm, nullptr, PSTR("Print file"), filelist.filename(), PSTR("from SD Card?"), true, true, false, true);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_StartPrint(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!filelist.seek(file_to_print)) return;
+ ExtUI::printFile(filelist.shortFilename());
+ GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_ResumePauseAbort(DGUS_VP_Variable &var, void *val_ptr) {
+
+ if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
+ switch (swap16(*(uint16_t*)val_ptr)) {
+ case 0: { // Resume
+ if (ExtUI::isPrintingFromMediaPaused()) {
+ ExtUI::resumePrint();
+ }
+ } break;
+
+ case 1: // Pause
+
+ GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
+ if (!ExtUI::isPrintingFromMediaPaused()) {
+ ExtUI::pausePrint();
+ //ExtUI::mks_pausePrint();
+ }
+ break;
+ case 2: // Abort
+ HandleUserConfirmationPopUp(VP_SD_AbortPrintConfirmed, nullptr, PSTR("Abort printing"), filelist.filename(), PSTR("?"), true, true, false, true);
+ break;
+ }
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_SendFilename(DGUS_VP_Variable& var) {
+ uint16_t target_line = (var.VP - VP_SD_FileName0) / VP_SD_FileName_LEN;
+ if (target_line > DGUS_SD_FILESPERSCREEN) return;
+ char tmpfilename[VP_SD_FileName_LEN + 1] = "";
+ var.memadr = (void*)tmpfilename;
+
+ if (filelist.seek(top_file + target_line)) {
+ snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s%c"), filelist.filename(), filelist.isDir() ? '/' : 0); // snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s"), filelist.filename());
+ }
+ DGUSLCD_SendStringToDisplay(var);
+ }
+
+ void DGUSScreenHandler::SDCardInserted() {
+ top_file = 0;
+ filelist.refresh();
+ auto cs = getCurrentScreen();
+ if (cs == DGUSLCD_SCREEN_MAIN || cs == DGUSLCD_SCREEN_STATUS)
+ GotoScreen(DGUSLCD_SCREEN_SDFILELIST);
+ }
+
+ void DGUSScreenHandler::SDCardRemoved() {
+ if (current_screen == DGUSLCD_SCREEN_SDFILELIST
+ || (current_screen == DGUSLCD_SCREEN_CONFIRM && (ConfirmVP == VP_SD_AbortPrintConfirmed || ConfirmVP == VP_SD_FileSelectConfirm))
+ || current_screen == DGUSLCD_SCREEN_SDPRINTMANIPULATION
+ ) GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+
+#endif // SDSUPPORT
+
+void DGUSScreenHandler::ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr) {
+ uint8_t *tmp = (uint8_t*)val_ptr;
+
+ // The keycode in target is coded as , so 0x0100A means
+ // from screen 1 (main) to 10 (temperature). DGUSLCD_SCREEN_POPUP is special,
+ // meaning "return to previous screen"
+ DGUSLCD_Screens target = (DGUSLCD_Screens)tmp[1];
+
+ DEBUG_ECHOLNPGM("\n DEBUG target", target);
+
+ if (target == DGUSLCD_SCREEN_POPUP) {
+ // Special handling for popup is to return to previous menu
+ if (current_screen == DGUSLCD_SCREEN_POPUP && confirm_action_cb) confirm_action_cb();
+ PopToOldScreen();
+ return;
+ }
+
+ UpdateNewScreen(target);
+
+ #ifdef DEBUG_DGUSLCD
+ if (!DGUSLCD_FindScreenVPMapList(target)) DEBUG_ECHOLNPGM("WARNING: No screen Mapping found for ", target);
+ #endif
+}
+
+void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleManualMove");
+
+ int16_t movevalue = swap16(*(uint16_t*)val_ptr);
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ if (movevalue) {
+ const uint16_t choice = *(uint16_t*)var.memadr;
+ movevalue = movevalue < 0 ? -choice : choice;
+ }
+ #endif
+ char axiscode;
+ unsigned int speed = 1500; // FIXME: get default feedrate for manual moves, don't hardcode.
+
+ switch (var.VP) {
+ default: return;
+
+ case VP_MOVE_X:
+ axiscode = 'X';
+ if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Y:
+ axiscode = 'Y';
+ if (!ExtUI::canMove(ExtUI::axis_t::Y)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Z:
+ axiscode = 'Z';
+ speed = 300; // default to 5mm/s
+ if (!ExtUI::canMove(ExtUI::axis_t::Z)) goto cannotmove;
+ break;
+
+ case VP_HOME_ALL: // only used for homing
+ axiscode = '\0';
+ movevalue = 0; // ignore value sent from display, this VP is _ONLY_ for homing.
+ break;
+ }
+
+ if (!movevalue) {
+ // homing
+ DEBUG_ECHOPGM(" homing ", AS_CHAR(axiscode));
+ char buf[6] = "G28 X";
+ buf[4] = axiscode;
+ //DEBUG_ECHOPGM(" ", buf);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOLNPGM(" ✓");
+ ForceCompleteUpdate();
+ return;
+ }
+ else {
+ // movement
+ DEBUG_ECHOPGM(" move ", AS_CHAR(axiscode));
+ bool old_relative_mode = relative_mode;
+ if (!relative_mode) {
+ //DEBUG_ECHOPGM(" G91");
+ queue.enqueue_now(F("G91"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ char buf[32]; // G1 X9999.99 F12345
+ unsigned int backup_speed = MMS_TO_MMM(feedrate_mm_s);
+ char sign[] = "\0";
+ int16_t value = movevalue / 100;
+ if (movevalue < 0) { value = -value; sign[0] = '-'; }
+ int16_t fraction = ABS(movevalue) % 100;
+ snprintf_P(buf, 32, PSTR("G0 %c%s%d.%02d F%d"), axiscode, sign, value, fraction, speed);
+ //DEBUG_ECHOPGM(" ", buf);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOLNPGM(" ✓ ");
+ if (backup_speed != speed) {
+ snprintf_P(buf, 32, PSTR("G0 F%d"), backup_speed);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOPGM(" ", buf);
+ }
+ // while (!enqueue_and_echo_command(buf)) idle();
+ //DEBUG_ECHOLNPGM(" ✓ ");
+ if (!old_relative_mode) {
+ //DEBUG_ECHOPGM("G90");
+ queue.enqueue_now(F("G90"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ }
+
+ ForceCompleteUpdate();
+ DEBUG_ECHOLNPGM("manmv done.");
+ return;
+
+ cannotmove:
+ DEBUG_ECHOLNPGM(" cannot move ", AS_CHAR(axiscode));
+ return;
+}
+
+#if HAS_PID_HEATING
+ void DGUSScreenHandler::HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t rawvalue = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("V1:", rawvalue);
+ float value = (float)rawvalue / 10;
+ DEBUG_ECHOLNPGM("V2:", value);
+ float newvalue = 0;
+
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_PID_P: newvalue = value; break;
+ case VP_E0_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E0_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_PID_P: newvalue = value; break;
+ case VP_E1_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E1_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HAS_HEATED_BED
+ case VP_BED_PID_P: newvalue = value; break;
+ case VP_BED_PID_I: newvalue = scalePID_i(value); break;
+ case VP_BED_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ }
+
+ DEBUG_ECHOLNPGM("V3:", newvalue);
+ *(float *)var.memadr = newvalue;
+
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ }
+#endif // HAS_PID_HEATING
+
+#if ENABLED(BABYSTEPPING)
+ void DGUSScreenHandler::HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleLiveAdjustZ");
+ int16_t flag = swap16(*(uint16_t*)val_ptr),
+ steps = flag ? -20 : 20;
+ ExtUI::smartAdjustAxis_steps(steps, ExtUI::axis_t::Z, true);
+ ForceCompleteUpdate();
+ }
+#endif
+
+#if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+
+ void DGUSScreenHandler::HandleFilamentOption(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleFilamentOption");
+
+ uint8_t e_temp = 0;
+ filament_data.heated = false;
+ uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
+ if (preheat_option <= 8) { // Load filament type
+ filament_data.action = 1;
+ }
+ else if (preheat_option >= 10) { // Unload filament type
+ preheat_option -= 10;
+ filament_data.action = 2;
+ filament_data.purge_length = DGUS_FILAMENT_PURGE_LENGTH;
+ }
+ else { // Cancel filament operation
+ filament_data.action = 0;
+ }
+
+ switch (preheat_option) {
+ case 0: // Load PLA
+ #ifdef PREHEAT_1_TEMP_HOTEND
+ e_temp = PREHEAT_1_TEMP_HOTEND;
+ #endif
+ break;
+ case 1: // Load ABS
+ TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND);
+ break;
+ case 2: // Load PET
+ #ifdef PREHEAT_3_TEMP_HOTEND
+ e_temp = PREHEAT_3_TEMP_HOTEND;
+ #endif
+ break;
+ case 3: // Load FLEX
+ #ifdef PREHEAT_4_TEMP_HOTEND
+ e_temp = PREHEAT_4_TEMP_HOTEND;
+ #endif
+ break;
+ case 9: // Cool down
+ default:
+ e_temp = 0;
+ break;
+ }
+
+ if (filament_data.action == 0) { // Go back to utility screen
+ #if HAS_HOTEND
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0);
+ #if HAS_MULTI_HOTEND
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1);
+ #endif
+ #endif
+ GotoScreen(DGUSLCD_SCREEN_UTILITY);
+ }
+ else { // Go to the preheat screen to show the heating progress
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E0;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E1;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ }
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_HEATING);
+ }
+ }
+
+ void DGUSScreenHandler::HandleFilamentLoadUnload(DGUS_VP_Variable &var) {
+ DEBUG_ECHOLNPGM("HandleFilamentLoadUnload");
+ if (filament_data.action <= 0) return;
+
+ // If we close to the target temperature, we can start load or unload the filament
+ if (thermalManager.hotEnoughToExtrude(filament_data.extruder) && \
+ thermalManager.targetHotEnoughToExtrude(filament_data.extruder)) {
+ float movevalue = DGUS_FILAMENT_LOAD_LENGTH_PER_TIME;
+
+ if (filament_data.action == 1) { // load filament
+ if (!filament_data.heated) {
+ //GotoScreen(DGUSLCD_SCREEN_FILAMENT_LOADING);
+ filament_data.heated = true;
+ }
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
+ }
+ else { // unload filament
+ if (!filament_data.heated) {
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_UNLOADING);
+ filament_data.heated = true;
+ }
+ // Before unloading extrude to prevent jamming
+ if (filament_data.purge_length >= 0) {
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
+ filament_data.purge_length -= movevalue;
+ }
+ else {
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue;
+ }
+ }
+ ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder);
+ }
+ }
+#endif // DGUS_FILAMENT_LOADUNLOAD
+
+bool DGUSScreenHandler::loop() {
+ dgusdisplay.loop();
+
+ const millis_t ms = millis();
+ static millis_t next_event_ms = 0;
+
+ if (!IsScreenComplete() || ELAPSED(ms, next_event_ms)) {
+ next_event_ms = ms + DGUS_UPDATE_INTERVAL_MS;
+ UpdateScreenVPData();
+ }
+
+ #if ENABLED(SHOW_BOOTSCREEN)
+ static bool booted = false;
+
+ if (!booted && TERN0(POWER_LOSS_RECOVERY, recovery.valid()))
+ booted = true;
+
+ if (!booted && ELAPSED(ms, BOOTSCREEN_TIMEOUT)) {
+ booted = true;
+ GotoScreen(TERN0(POWER_LOSS_RECOVERY, recovery.valid()) ? DGUSLCD_SCREEN_POWER_LOSS : DGUSLCD_SCREEN_MAIN);
+ }
+ #endif
+
+ return IsScreenComplete();
+}
+
+#endif // DGUS_LCD_UI_FYSETC
diff --git a/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.h b/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.h
new file mode 100644
index 0000000..73e3527
--- /dev/null
+++ b/src/lcd/extui/dgus/fysetc/DGUSScreenHandler.h
@@ -0,0 +1,31 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+#include "../DGUSScreenHandlerBase.h"
+
+typedef DGUSScreenHandler DGUSScreenHandlerClass;
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #define PLR_SCREEN_RECOVER DGUSLCD_SCREEN_SDPRINTMANIPULATION
+ #define PLR_SCREEN_CANCEL DGUSLCD_SCREEN_STATUS
+#endif
diff --git a/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp b/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp
new file mode 100644
index 0000000..4c85018
--- /dev/null
+++ b/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.cpp
@@ -0,0 +1,471 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/* DGUS VPs changed by George Fu in 2019 for Marlin */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_HIPRECY)
+
+#include "DGUSDisplayDef.h"
+#include "../DGUSDisplay.h"
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+
+#include "../../ui_api.h"
+#include "../../../marlinui.h"
+
+#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ uint16_t distanceToMove = 10;
+#endif
+
+const uint16_t VPList_Boot[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ 0x0000
+};
+
+const uint16_t VPList_Main[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded.
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set, VP_E0_STATUS,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set, VP_BED_STATUS,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage, VP_FAN0_STATUS,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ #if ENABLED(LCD_SET_PROGRESS_MANUALLY)
+ VP_PrintProgress_Percentage,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Temp[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Status[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ VP_PrintProgress_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_Status2[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded
+ #if HAS_HOTEND
+ VP_Flowrate_E0,
+ #if HAS_MULTI_HOTEND
+ VP_Flowrate_E1,
+ #endif
+ #endif
+ VP_PrintProgress_Percentage,
+ VP_PrintTime,
+ 0x0000
+};
+
+const uint16_t VPList_Preheat[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_ManualMove[] PROGMEM = {
+ VP_XPos, VP_YPos, VP_ZPos,
+ 0x0000
+};
+
+const uint16_t VPList_ManualExtrude[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ VP_EPos,
+ 0x0000
+};
+
+const uint16_t VPList_FanAndFeedrate[] PROGMEM = {
+ VP_Feedrate_Percentage, VP_Fan0_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_SD_FlowRates[] PROGMEM = {
+ VP_Flowrate_E0, VP_Flowrate_E1,
+ 0x0000
+};
+
+const uint16_t VPList_Filament_heating[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ VP_E0_FILAMENT_LOAD_UNLOAD,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Filament_load_unload[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_E0_FILAMENT_LOAD_UNLOAD,
+ #if HAS_MULTI_HOTEND
+ VP_E1_FILAMENT_LOAD_UNLOAD,
+ #endif
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_SDFileList[] PROGMEM = {
+ VP_SD_FileName0, VP_SD_FileName1, VP_SD_FileName2, VP_SD_FileName3, VP_SD_FileName4,
+ 0x0000
+};
+
+const uint16_t VPList_SD_PrintManipulation[] PROGMEM = {
+ VP_PrintProgress_Percentage, VP_PrintTime,
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #if FAN_COUNT > 1
+ VP_Fan1_Percentage,
+ #endif
+ #endif
+ VP_Flowrate_E0,
+ 0x0000
+};
+
+const uint16_t VPList_SDPrintTune[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ VP_Feedrate_Percentage,
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #endif
+ VP_Flowrate_E0,
+ VP_SD_Print_ProbeOffsetZ,
+ 0x0000
+};
+
+const uint16_t VPList_StepPerMM[] PROGMEM = {
+ VP_X_STEP_PER_MM,
+ VP_Y_STEP_PER_MM,
+ VP_Z_STEP_PER_MM,
+ OPTITEM(HAS_HOTEND, VP_E0_STEP_PER_MM)
+ OPTITEM(HAS_MULTI_HOTEND, VP_E1_STEP_PER_MM)
+ 0x0000
+};
+
+const uint16_t VPList_PIDE0[] PROGMEM = {
+ #if ENABLED(PIDTEMP)
+ VP_E0_PID_P, VP_E0_PID_I, VP_E0_PID_D,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDBED[] PROGMEM = {
+ #if ENABLED(PIDTEMP)
+ VP_BED_PID_P,
+ VP_BED_PID_I,
+ VP_BED_PID_D,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Infos[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ VP_PrintTime,
+ #if ENABLED(PRINTCOUNTER)
+ VP_PrintAccTime,
+ VP_PrintsTotal,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_PIDTuningWaiting[] PROGMEM = {
+ VP_WAITING_STATUS,
+ 0x0000
+};
+
+const uint16_t VPList_FLCPreheat[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_FLCPrinting[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_SD_Print_ProbeOffsetZ,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Z_Offset[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_SD_Print_ProbeOffsetZ,
+ #endif
+ 0x0000
+};
+
+const struct VPMapping VPMap[] PROGMEM = {
+ { DGUSLCD_SCREEN_BOOT, VPList_Boot },
+ { DGUSLCD_SCREEN_MAIN, VPList_Main },
+ { DGUSLCD_SCREEN_TEMPERATURE, VPList_Temp },
+ { DGUSLCD_SCREEN_STATUS, VPList_Status },
+ { DGUSLCD_SCREEN_STATUS2, VPList_Status2 },
+ { DGUSLCD_SCREEN_PREHEAT, VPList_Preheat },
+ { DGUSLCD_SCREEN_MANUALMOVE, VPList_ManualMove },
+ { DGUSLCD_SCREEN_Z_OFFSET, VPList_Z_Offset },
+ { DGUSLCD_SCREEN_MANUALEXTRUDE, VPList_ManualExtrude },
+ { DGUSLCD_SCREEN_FILAMENT_HEATING, VPList_Filament_heating },
+ { DGUSLCD_SCREEN_FILAMENT_LOADING, VPList_Filament_load_unload },
+ { DGUSLCD_SCREEN_FILAMENT_UNLOADING, VPList_Filament_load_unload },
+ { DGUSLCD_SCREEN_SDPRINTMANIPULATION, VPList_SD_PrintManipulation },
+ { DGUSLCD_SCREEN_SDFILELIST, VPList_SDFileList },
+ { DGUSLCD_SCREEN_SDPRINTTUNE, VPList_SDPrintTune },
+ { DGUSLCD_SCREEN_WAITING, VPList_PIDTuningWaiting },
+ { DGUSLCD_SCREEN_FLC_PREHEAT, VPList_FLCPreheat },
+ { DGUSLCD_SCREEN_FLC_PRINTING, VPList_FLCPrinting },
+ { DGUSLCD_SCREEN_STEPPERMM, VPList_StepPerMM },
+ { DGUSLCD_SCREEN_PID_E, VPList_PIDE0 },
+ { DGUSLCD_SCREEN_PID_BED, VPList_PIDBED },
+ { DGUSLCD_SCREEN_INFOS, VPList_Infos },
+ { 0 , nullptr } // List is terminated with an nullptr as table entry.
+};
+
+const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION;
+
+const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
+ // Helper to detect touch events
+ VPHELPER(VP_SCREENCHANGE, nullptr, ScreenHandler.ScreenChangeHook, nullptr),
+ VPHELPER(VP_SCREENCHANGE_ASK, nullptr, ScreenHandler.ScreenChangeHookIfIdle, nullptr),
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SCREENCHANGE_WHENSD, nullptr, ScreenHandler.ScreenChangeHookIfSD, nullptr),
+ #endif
+ VPHELPER(VP_CONFIRMED, nullptr, ScreenHandler.ScreenConfirmedOK, nullptr),
+
+ VPHELPER(VP_TEMP_ALL_OFF, nullptr, ScreenHandler.HandleAllHeatersOff, nullptr),
+
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_OPTION, &distanceToMove, ScreenHandler.HandleManualMoveOption, nullptr),
+ #endif
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_X, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ #else
+ VPHELPER(VP_MOVE_X, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ #endif
+ VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, ScreenHandler.HandleMotorLockUnlock, nullptr),
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, ScreenHandler.HandlePowerLossRecovery, nullptr),
+ #endif
+ VPHELPER(VP_SETTINGS, nullptr, ScreenHandler.HandleSettings, nullptr),
+ #if ENABLED(SINGLE_Z_CALIBRATION)
+ VPHELPER(VP_Z_CALIBRATE, nullptr, ScreenHandler.HandleZCalibration, nullptr),
+ #endif
+ #if ENABLED(FIRST_LAYER_CAL)
+ VPHELPER(VP_Z_FIRST_LAYER_CAL, nullptr, ScreenHandler.HandleFirstLayerCal, nullptr),
+ #endif
+
+ { .VP = VP_MARLIN_VERSION, .memadr = (void*)MarlinVersion, .size = VP_MARLIN_VERSION_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ // M117 LCD String (We don't need the string in memory but "just" push it to the display on demand, hence the nullptr
+ { .VP = VP_M117, .memadr = nullptr, .size = VP_M117_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplay },
+
+ // Temperature Data
+ #if HAS_HOTEND
+ VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[ExtUI::extruder_t::E0], ScreenHandler.HandleFlowRateChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_EPos, &destination.e, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_MOVE_E0, nullptr, ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E0_STATUS, &thermalManager.temp_hotend[0].target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(DGUS_PREHEAT_UI)
+ VPHELPER(VP_E0_BED_PREHEAT, nullptr, ScreenHandler.HandlePreheat, nullptr),
+ #endif
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ VPHELPER(VP_E0_FILAMENT_LOAD_UNLOAD, nullptr, ScreenHandler.HandleFilamentOption, ScreenHandler.HandleFilamentLoadUnload),
+ #endif
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_E0_PID_P, &thermalManager.temp_hotend[0].pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_I, &thermalManager.temp_hotend[0].pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_D, &thermalManager.temp_hotend[0].pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_E0, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #endif
+ #if HAS_MULTI_HOTEND
+ VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E1, nullptr, ScreenHandler.HandleFlowRateChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_MOVE_E1, nullptr, ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #endif
+ #if HAS_HEATED_BED
+ VPHELPER(VP_T_Bed_Is, &thermalManager.temp_bed.celsius, nullptr, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_T_Bed_Set, &thermalManager.temp_bed.target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_BED_CONTROL, &thermalManager.temp_bed.target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_BED_STATUS, &thermalManager.temp_bed.target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMPBED)
+ VPHELPER(VP_BED_PID_P, &thermalManager.temp_bed.pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_I, &thermalManager.temp_bed.pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_D, &thermalManager.temp_bed.pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_BED, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #endif
+
+ // Fan Data
+ #if HAS_FAN
+ #define FAN_VPHELPER(N) \
+ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], ScreenHandler.DGUSLCD_PercentageToUint8, ScreenHandler.DGUSLCD_SendPercentageToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], ScreenHandler.HandleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, ScreenHandler.DGUSLCD_SendFanStatusToDisplay),
+ REPEAT(FAN_COUNT, FAN_VPHELPER)
+ #endif
+
+ // Feedrate
+ VPHELPER(VP_Feedrate_Percentage, &feedrate_percentage, ScreenHandler.DGUSLCD_SetValueDirectly, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+
+ // Position Data
+ VPHELPER(VP_XPos, ¤t_position.x, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_YPos, ¤t_position.y, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_ZPos, ¤t_position.z, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+
+ // Print Progress
+ VPHELPER(VP_PrintProgress_Percentage, nullptr, nullptr, ScreenHandler.DGUSLCD_SendPrintProgressToDisplay),
+
+ // Print Time
+ VPHELPER_STR(VP_PrintTime, nullptr, VP_PrintTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeToDisplay),
+ #if ENABLED(PRINTCOUNTER)
+ VPHELPER_STR(VP_PrintAccTime, nullptr, VP_PrintAccTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintAccTimeToDisplay),
+ VPHELPER_STR(VP_PrintsTotal, nullptr, VP_PrintsTotal_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintsTotalToDisplay),
+ #endif
+
+ VPHELPER(VP_X_STEP_PER_MM, &planner.settings.axis_steps_per_mm[X_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Y_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Y_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Z_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Z_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #if HAS_HOTEND
+ VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #if HAS_MULTI_HOTEND
+ VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #endif
+ #endif
+
+ // SDCard File listing.
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SD_ScrollEvent, nullptr, ScreenHandler.DGUSLCD_SD_ScrollFilelist, nullptr),
+ VPHELPER(VP_SD_FileSelected, nullptr, ScreenHandler.DGUSLCD_SD_FileSelected, nullptr),
+ VPHELPER(VP_SD_FileSelectConfirm, nullptr, ScreenHandler.DGUSLCD_SD_StartPrint, nullptr),
+ VPHELPER_STR(VP_SD_FileName0, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName1, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName2, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName3, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName4, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER(VP_SD_ResumePauseAbort, nullptr, ScreenHandler.DGUSLCD_SD_ResumePauseAbort, nullptr),
+ VPHELPER(VP_SD_AbortPrintConfirmed, nullptr, ScreenHandler.DGUSLCD_SD_ReallyAbort, nullptr),
+ VPHELPER(VP_SD_Print_Setting, nullptr, ScreenHandler.DGUSLCD_SD_PrintTune, nullptr),
+ #if HAS_BED_PROBE
+ VPHELPER(VP_SD_Print_ProbeOffsetZ, &probe.offset.z, ScreenHandler.HandleProbeOffsetZChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<2>),
+ #if ENABLED(BABYSTEPPING)
+ VPHELPER(VP_SD_Print_LiveAdjustZ, nullptr, ScreenHandler.HandleLiveAdjustZ, nullptr),
+ #endif
+ #endif
+ #endif
+
+ #if ENABLED(DGUS_UI_WAITING)
+ VPHELPER(VP_WAITING_STATUS, nullptr, nullptr, ScreenHandler.DGUSLCD_SendWaitingStatusToDisplay),
+ #endif
+
+ // Messages for the User, shared by the popup and the kill screen. They can't be autouploaded as we do not buffer content.
+ { .VP = VP_MSGSTR1, .memadr = nullptr, .size = VP_MSGSTR1_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR2, .memadr = nullptr, .size = VP_MSGSTR2_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR3, .memadr = nullptr, .size = VP_MSGSTR3_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR4, .memadr = nullptr, .size = VP_MSGSTR4_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+
+ VPHELPER(0, 0, 0, 0) // must be last entry.
+};
+
+#endif // DGUS_LCD_UI_HIPRECY
diff --git a/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h b/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h
new file mode 100644
index 0000000..e958155
--- /dev/null
+++ b/src/lcd/extui/dgus/hiprecy/DGUSDisplayDef.h
@@ -0,0 +1,292 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+#include "../DGUSDisplayDef.h"
+
+enum DGUSLCD_Screens : uint8_t {
+ DGUSLCD_SCREEN_BOOT = 160,
+ DGUSLCD_SCREEN_MAIN = 1,
+ DGUSLCD_SCREEN_STATUS = 1,
+ DGUSLCD_SCREEN_STATUS2 = 1,
+ DGUSLCD_SCREEN_POWER_LOSS = 17,
+ DGUSLCD_SCREEN_TEMPERATURE = 40,
+ DGUSLCD_SCREEN_MANUALMOVE = 86,
+ DGUSLCD_SCREEN_PREHEAT = 48,
+ DGUSLCD_SCREEN_UTILITY = 70,
+ DGUSLCD_SCREEN_FILAMENT_HEATING = 80,
+ DGUSLCD_SCREEN_FILAMENT_LOADING = 76,
+ DGUSLCD_SCREEN_FILAMENT_UNLOADING = 82,
+ DGUSLCD_SCREEN_MANUALEXTRUDE = 84,
+ DGUSLCD_SCREEN_Z_OFFSET = 88,
+ DGUSLCD_SCREEN_SDFILELIST = 3,
+ DGUSLCD_SCREEN_SDPRINTMANIPULATION = 7,
+ DGUSLCD_SCREEN_SDPRINTTUNE = 9,
+ DGUSLCD_SCREEN_FLC_PREHEAT = 94,
+ DGUSLCD_SCREEN_FLC_PRINTING = 96,
+ DGUSLCD_SCREEN_STEPPERMM = 122,
+ DGUSLCD_SCREEN_PID_E = 126,
+ DGUSLCD_SCREEN_PID_BED = 128,
+ DGUSLCD_SCREEN_INFOS = 131,
+ DGUSLCD_SCREEN_CONFIRM = 240,
+ DGUSLCD_SCREEN_KILL = 250, ///< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version")
+ DGUSLCD_SCREEN_WAITING = 251,
+ DGUSLCD_SCREEN_POPUP = 252, ///< special target, popup screen will also return this code to say "return to previous screen"
+ DGUSLCD_SCREEN_UNUSED = 255
+};
+
+// Display Memory layout used (T5UID)
+// Except system variables this is arbitrary, just to organize stuff....
+
+// 0x0000 .. 0x0FFF -- System variables and reserved by the display
+// 0x1000 .. 0x1FFF -- Variables to never change location, regardless of UI Version
+// 0x2000 .. 0x2FFF -- Controls (VPs that will trigger some action)
+// 0x3000 .. 0x4FFF -- Marlin Data to be displayed
+// 0x5000 .. -- SPs (if we want to modify display elements, e.g change color or like) -- currently unused
+
+// As there is plenty of space (at least most displays have >8k RAM), we do not pack them too tight,
+// so that we can keep variables nicely together in the address space.
+
+// UI Version always on 0x1000...0x1002 so that the firmware can check this and bail out.
+constexpr uint16_t VP_UI_VERSION_MAJOR = 0x1000; // Major -- incremented when incompatible
+constexpr uint16_t VP_UI_VERSION_MINOR = 0x1001; // Minor -- incremented on new features, but compatible
+constexpr uint16_t VP_UI_VERSION_PATCH = 0x1002; // Patch -- fixed which do not change functionality.
+constexpr uint16_t VP_UI_FLAVOUR = 0x1010; // lets reserve 16 bytes here to determine if UI is suitable for this Marlin. tbd.
+
+// Storage space for the Killscreen messages. 0x1100 - 0x1200 . Reused for the popup.
+constexpr uint16_t VP_MSGSTR1 = 0x1100;
+constexpr uint8_t VP_MSGSTR1_LEN = 0x20; // might be more place for it...
+constexpr uint16_t VP_MSGSTR2 = 0x1140;
+constexpr uint8_t VP_MSGSTR2_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR3 = 0x1180;
+constexpr uint8_t VP_MSGSTR3_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR4 = 0x11C0;
+constexpr uint8_t VP_MSGSTR4_LEN = 0x20;
+
+// Screenchange request for screens that only make sense when printer is idle.
+// e.g movement is only allowed if printer is not printing.
+// Marlin must confirm by setting the screen manually.
+constexpr uint16_t VP_SCREENCHANGE_ASK = 0x2000;
+constexpr uint16_t VP_SCREENCHANGE = 0x2001; // Key-Return button to new menu pressed. Data contains target screen in low byte and info in high byte.
+constexpr uint16_t VP_TEMP_ALL_OFF = 0x2002; // Turn all heaters off. Value arbitrary ;)=
+constexpr uint16_t VP_SCREENCHANGE_WHENSD = 0x2003; // "Print" Button touched -- go only there if there is an SD Card.
+
+constexpr uint16_t VP_CONFIRMED = 0x2010; // OK on confirm screen.
+
+// Buttons on the SD-Card File listing.
+constexpr uint16_t VP_SD_ScrollEvent = 0x2020; // Data: 0 for "up a directory", numbers are the amount to scroll, e.g -1 one up, 1 one down
+constexpr uint16_t VP_SD_FileSelected = 0x2022; // Number of file field selected.
+constexpr uint16_t VP_SD_FileSelectConfirm = 0x2024; // (This is a virtual VP and emulated by the Confirm Screen when a file has been confirmed)
+
+constexpr uint16_t VP_SD_ResumePauseAbort = 0x2026; // Resume(Data=0), Pause(Data=1), Abort(Data=2) SD Card prints
+constexpr uint16_t VP_SD_AbortPrintConfirmed = 0x2028; // Abort print confirmation (virtual, will be injected by the confirm dialog)
+constexpr uint16_t VP_SD_Print_Setting = 0x2040;
+constexpr uint16_t VP_SD_Print_LiveAdjustZ = 0x2050; // Data: 0 down, 1 up
+
+// Controls for movement (we can't use the incremental / decremental feature of the display at this feature works only with 16 bit values
+// (which would limit us to 655.35mm, which is likely not a problem for common setups, but i don't want to rule out hangprinters support)
+// A word about the coding: The VP will be per axis and the return code will be an signed 16 bit value in 0.01 mm resolution, telling us
+// the relative travel amount t he user wants to do. So eg. if the display sends us VP=2100 with value 100, the user wants us to move X by +1 mm.
+constexpr uint16_t VP_MOVE_X = 0x2100;
+constexpr uint16_t VP_MOVE_Y = 0x2102;
+constexpr uint16_t VP_MOVE_Z = 0x2104;
+constexpr uint16_t VP_MOVE_E0 = 0x2110;
+constexpr uint16_t VP_MOVE_E1 = 0x2112;
+//constexpr uint16_t VP_MOVE_E2 = 0x2114;
+//constexpr uint16_t VP_MOVE_E3 = 0x2116;
+//constexpr uint16_t VP_MOVE_E4 = 0x2118;
+//constexpr uint16_t VP_MOVE_E5 = 0x211A;
+constexpr uint16_t VP_HOME_ALL = 0x2120;
+constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130;
+
+// Power loss recovery
+constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180;
+
+// Fan Control Buttons , switch between "off" and "on"
+constexpr uint16_t VP_FAN0_CONTROL = 0x2200;
+constexpr uint16_t VP_FAN1_CONTROL = 0x2202;
+//constexpr uint16_t VP_FAN2_CONTROL = 0x2204;
+//constexpr uint16_t VP_FAN3_CONTROL = 0x2206;
+
+// Heater Control Buttons , triged between "cool down" and "heat PLA" state
+constexpr uint16_t VP_E0_CONTROL = 0x2210;
+constexpr uint16_t VP_E1_CONTROL = 0x2212;
+//constexpr uint16_t VP_E2_CONTROL = 0x2214;
+//constexpr uint16_t VP_E3_CONTROL = 0x2216;
+//constexpr uint16_t VP_E4_CONTROL = 0x2218;
+//constexpr uint16_t VP_E5_CONTROL = 0x221A;
+constexpr uint16_t VP_BED_CONTROL = 0x221C;
+
+// Preheat
+constexpr uint16_t VP_E0_BED_PREHEAT = 0x2220;
+//constexpr uint16_t VP_E1_BED_PREHEAT = 0x2222;
+//constexpr uint16_t VP_E2_BED_PREHEAT = 0x2224;
+//constexpr uint16_t VP_E3_BED_PREHEAT = 0x2226;
+//constexpr uint16_t VP_E4_BED_PREHEAT = 0x2228;
+//constexpr uint16_t VP_E5_BED_PREHEAT = 0x222A;
+
+// Filament load and unload
+constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300;
+
+// Settings store , reset
+constexpr uint16_t VP_SETTINGS = 0x2400;
+
+// PID autotune
+constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x2410;
+//constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x2412;
+//constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x2414;
+//constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x2416;
+//constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x2418;
+//constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x241A;
+constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x2420;
+
+// Calibrate Z
+constexpr uint16_t VP_Z_CALIBRATE = 0x2430;
+
+// First layer cal
+constexpr uint16_t VP_Z_FIRST_LAYER_CAL = 0x2500; // Data: 0 - Cancel first layer cal progress, >0 filament type have loaded
+
+// Firmware version on the boot screen.
+constexpr uint16_t VP_MARLIN_VERSION = 0x3000;
+constexpr uint8_t VP_MARLIN_VERSION_LEN = 16; // there is more space on the display, if needed.
+
+// Place for status messages.
+constexpr uint16_t VP_M117 = 0x3020;
+constexpr uint8_t VP_M117_LEN = 0x20;
+
+// Temperatures.
+constexpr uint16_t VP_T_E0_Is = 0x3060; // 4 Byte Integer
+constexpr uint16_t VP_T_E0_Set = 0x3062; // 2 Byte Integer
+constexpr uint16_t VP_T_E1_Is = 0x3064; // 4 Byte Integer
+
+// reserved to support up to 6 Extruders:
+//constexpr uint16_t VP_T_E1_Set = 0x3066; // 2 Byte Integer
+//constexpr uint16_t VP_T_E2_Is = 0x3068; // 4 Byte Integer
+//constexpr uint16_t VP_T_E2_Set = 0x306A; // 2 Byte Integer
+//constexpr uint16_t VP_T_E3_Is = 0x306C; // 4 Byte Integer
+//constexpr uint16_t VP_T_E3_Set = 0x306E; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3070; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3072; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3074; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3076; // 2 Byte Integer
+//constexpr uint16_t VP_T_E5_Is = 0x3078; // 4 Byte Integer
+//constexpr uint16_t VP_T_E5_Set = 0x307A; // 2 Byte Integer
+
+constexpr uint16_t VP_T_Bed_Is = 0x3080; // 4 Byte Integer
+constexpr uint16_t VP_T_Bed_Set = 0x3082; // 2 Byte Integer
+
+constexpr uint16_t VP_Flowrate_E0 = 0x3090; // 2 Byte Integer
+constexpr uint16_t VP_Flowrate_E1 = 0x3092; // 2 Byte Integer
+
+// reserved for up to 6 Extruders:
+//constexpr uint16_t VP_Flowrate_E2 = 0x3094;
+//constexpr uint16_t VP_Flowrate_E3 = 0x3096;
+//constexpr uint16_t VP_Flowrate_E4 = 0x3098;
+//constexpr uint16_t VP_Flowrate_E5 = 0x309A;
+
+constexpr uint16_t VP_Fan0_Percentage = 0x3100; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan1_Percentage = 0x3102; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan2_Percentage = 0x3104; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan3_Percentage = 0x3106; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Feedrate_Percentage = 0x3108; // 2 Byte Integer (0..100)
+
+// Actual Position
+constexpr uint16_t VP_XPos = 0x3110; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_YPos = 0x3112; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_ZPos = 0x3114; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_EPos = 0x3120; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_PrintProgress_Percentage = 0x3130; // 2 Byte Integer (0..100)
+
+constexpr uint16_t VP_PrintTime = 0x3140;
+constexpr uint16_t VP_PrintTime_LEN = 32;
+
+constexpr uint16_t VP_PrintAccTime = 0x3160;
+constexpr uint16_t VP_PrintAccTime_LEN = 32;
+
+constexpr uint16_t VP_PrintsTotal = 0x3180;
+constexpr uint16_t VP_PrintsTotal_LEN = 16;
+
+// SDCard File Listing
+constexpr uint16_t VP_SD_FileName_LEN = 32; // LEN is shared for all entries.
+constexpr uint16_t DGUS_SD_FILESPERSCREEN = 5; // FIXME move that info to the display and read it from there.
+constexpr uint16_t VP_SD_FileName0 = 0x3200;
+constexpr uint16_t VP_SD_FileName1 = 0x3220;
+constexpr uint16_t VP_SD_FileName2 = 0x3240;
+constexpr uint16_t VP_SD_FileName3 = 0x3260;
+constexpr uint16_t VP_SD_FileName4 = 0x3280;
+
+constexpr uint16_t VP_SD_Print_ProbeOffsetZ = 0x32A0; //
+
+constexpr uint16_t VP_SD_Print_Filename = 0x32C0; //
+// Fan status
+constexpr uint16_t VP_FAN0_STATUS = 0x3300;
+constexpr uint16_t VP_FAN1_STATUS = 0x3302;
+//constexpr uint16_t VP_FAN2_STATUS = 0x3304;
+//constexpr uint16_t VP_FAN3_STATUS = 0x3306;
+
+// Heater status
+constexpr uint16_t VP_E0_STATUS = 0x3310;
+//constexpr uint16_t VP_E1_STATUS = 0x3312;
+//constexpr uint16_t VP_E2_STATUS = 0x3314;
+//constexpr uint16_t VP_E3_STATUS = 0x3316;
+//constexpr uint16_t VP_E4_STATUS = 0x3318;
+//constexpr uint16_t VP_E5_STATUS = 0x331A;
+constexpr uint16_t VP_BED_STATUS = 0x331C;
+
+constexpr uint16_t VP_MOVE_OPTION = 0x3400;
+
+// Step per mm
+constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment , 2 byte unsigned int , 0~1638.4
+//constexpr uint16_t VP_X2_STEP_PER_MM = 0x3602;
+constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604;
+//constexpr uint16_t VP_Y2_STEP_PER_MM = 0x3606;
+constexpr uint16_t VP_Z_STEP_PER_MM = 0x3608;
+//constexpr uint16_t VP_Z2_STEP_PER_MM = 0x360A;
+constexpr uint16_t VP_E0_STEP_PER_MM = 0x3610;
+//constexpr uint16_t VP_E1_STEP_PER_MM = 0x3612;
+//constexpr uint16_t VP_E2_STEP_PER_MM = 0x3614;
+//constexpr uint16_t VP_E3_STEP_PER_MM = 0x3616;
+//constexpr uint16_t VP_E4_STEP_PER_MM = 0x3618;
+//constexpr uint16_t VP_E5_STEP_PER_MM = 0x361A;
+
+// PIDs
+constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , 2 byte unsigned int , 0~1638.4
+constexpr uint16_t VP_E0_PID_I = 0x3702;
+constexpr uint16_t VP_E0_PID_D = 0x3704;
+constexpr uint16_t VP_BED_PID_P = 0x3710;
+constexpr uint16_t VP_BED_PID_I = 0x3712;
+constexpr uint16_t VP_BED_PID_D = 0x3714;
+
+// Waiting screen status
+constexpr uint16_t VP_WAITING_STATUS = 0x3800;
+
+// SPs for certain variables...
+// located at 0x5000 and up
+// Not used yet!
+// This can be used e.g to make controls / data display invisible
+constexpr uint16_t SP_T_E0_Is = 0x5000;
+constexpr uint16_t SP_T_E0_Set = 0x5010;
+constexpr uint16_t SP_T_E1_Is = 0x5020;
+constexpr uint16_t SP_T_Bed_Is = 0x5030;
+constexpr uint16_t SP_T_Bed_Set = 0x5040;
diff --git a/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.cpp b/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.cpp
new file mode 100644
index 0000000..f04bef2
--- /dev/null
+++ b/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.cpp
@@ -0,0 +1,423 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_HIPRECY)
+
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../MarlinCore.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../libs/duration_t.h"
+#include "../../../../module/settings.h"
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+#include "../../../../module/printcounter.h"
+#include "../../../../sd/cardreader.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if ENABLED(SDSUPPORT)
+
+ extern ExtUI::FileList filelist;
+
+ void DGUSScreenHandler::DGUSLCD_SD_FileSelected(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t touched_nr = (int16_t)swap16(*(uint16_t*)val_ptr) + top_file;
+ if (touched_nr > filelist.count()) return;
+ if (!filelist.seek(touched_nr)) return;
+
+ if (filelist.isDir()) {
+ filelist.changeDir(filelist.filename());
+ top_file = 0;
+ ForceCompleteUpdate();
+ return;
+ }
+
+ #if ENABLED(DGUS_PRINT_FILENAME)
+ // Send print filename
+ dgusdisplay.WriteVariable(VP_SD_Print_Filename, filelist.filename(), VP_SD_FileName_LEN, true);
+ #endif
+
+ // Setup Confirmation screen
+ file_to_print = touched_nr;
+
+ HandleUserConfirmationPopUp(VP_SD_FileSelectConfirm, nullptr, PSTR("Print file"), filelist.filename(), PSTR("from SD Card?"), true, true, false, true);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_StartPrint(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!filelist.seek(file_to_print)) return;
+ ExtUI::printFile(filelist.shortFilename());
+ GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_ResumePauseAbort(DGUS_VP_Variable &var, void *val_ptr) {
+
+ if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
+ switch (swap16(*(uint16_t*)val_ptr)) {
+ case 0: { // Resume
+ if (ExtUI::isPrintingFromMediaPaused()) {
+ ExtUI::resumePrint();
+ }
+ } break;
+
+ case 1: // Pause
+
+ GotoScreen(MKSLCD_SCREEN_PAUSE);
+ if (!ExtUI::isPrintingFromMediaPaused()) {
+ ExtUI::pausePrint();
+ //ExtUI::mks_pausePrint();
+ }
+ break;
+ case 2: // Abort
+ HandleUserConfirmationPopUp(VP_SD_AbortPrintConfirmed, nullptr, PSTR("Abort printing"), filelist.filename(), PSTR("?"), true, true, false, true);
+ break;
+ }
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_SendFilename(DGUS_VP_Variable& var) {
+ uint16_t target_line = (var.VP - VP_SD_FileName0) / VP_SD_FileName_LEN;
+ if (target_line > DGUS_SD_FILESPERSCREEN) return;
+ char tmpfilename[VP_SD_FileName_LEN + 1] = "";
+ var.memadr = (void*)tmpfilename;
+
+ if (filelist.seek(top_file + target_line)) {
+ snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s%c"), filelist.filename(), filelist.isDir() ? '/' : 0); // snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s"), filelist.filename());
+ }
+ DGUSLCD_SendStringToDisplay(var);
+ }
+
+ void DGUSScreenHandler::SDCardInserted() {
+ top_file = 0;
+ filelist.refresh();
+ auto cs = getCurrentScreen();
+ if (cs == DGUSLCD_SCREEN_MAIN || cs == DGUSLCD_SCREEN_STATUS)
+ GotoScreen(DGUSLCD_SCREEN_SDFILELIST);
+ }
+
+ void DGUSScreenHandler::SDCardRemoved() {
+ if (current_screen == DGUSLCD_SCREEN_SDFILELIST
+ || (current_screen == DGUSLCD_SCREEN_CONFIRM && (ConfirmVP == VP_SD_AbortPrintConfirmed || ConfirmVP == VP_SD_FileSelectConfirm))
+ || current_screen == DGUSLCD_SCREEN_SDPRINTMANIPULATION
+ ) GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+
+#endif // SDSUPPORT
+
+void DGUSScreenHandler::ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr) {
+ uint8_t *tmp = (uint8_t*)val_ptr;
+
+ // The keycode in target is coded as , so 0x0100A means
+ // from screen 1 (main) to 10 (temperature). DGUSLCD_SCREEN_POPUP is special,
+ // meaning "return to previous screen"
+ DGUSLCD_Screens target = (DGUSLCD_Screens)tmp[1];
+
+ DEBUG_ECHOLNPGM("\n DEBUG target", target);
+
+ if (target == DGUSLCD_SCREEN_POPUP) {
+ // Special handling for popup is to return to previous menu
+ if (current_screen == DGUSLCD_SCREEN_POPUP && confirm_action_cb) confirm_action_cb();
+ PopToOldScreen();
+ return;
+ }
+
+ UpdateNewScreen(target);
+
+ #ifdef DEBUG_DGUSLCD
+ if (!DGUSLCD_FindScreenVPMapList(target)) DEBUG_ECHOLNPGM("WARNING: No screen Mapping found for ", target);
+ #endif
+}
+
+void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleManualMove");
+
+ int16_t movevalue = swap16(*(uint16_t*)val_ptr);
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ if (movevalue) {
+ const uint16_t choice = *(uint16_t*)var.memadr;
+ movevalue = movevalue < 0 ? -choice : choice;
+ }
+ #endif
+ char axiscode;
+ unsigned int speed = 1500; // FIXME: get default feedrate for manual moves, don't hardcode.
+
+ switch (var.VP) {
+ default: return;
+
+ case VP_MOVE_X:
+ axiscode = 'X';
+ if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Y:
+ axiscode = 'Y';
+ if (!ExtUI::canMove(ExtUI::axis_t::Y)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Z:
+ axiscode = 'Z';
+ speed = 300; // default to 5mm/s
+ if (!ExtUI::canMove(ExtUI::axis_t::Z)) goto cannotmove;
+ break;
+
+ case VP_HOME_ALL: // only used for homing
+ axiscode = '\0';
+ movevalue = 0; // ignore value sent from display, this VP is _ONLY_ for homing.
+ break;
+ }
+
+ if (!movevalue) {
+ // homing
+ DEBUG_ECHOPGM(" homing ", AS_CHAR(axiscode));
+ char buf[6] = "G28 X";
+ buf[4] = axiscode;
+ //DEBUG_ECHOPGM(" ", buf);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOLNPGM(" ✓");
+ ForceCompleteUpdate();
+ return;
+ }
+ else {
+ // movement
+ DEBUG_ECHOPGM(" move ", AS_CHAR(axiscode));
+ bool old_relative_mode = relative_mode;
+ if (!relative_mode) {
+ //DEBUG_ECHOPGM(" G91");
+ queue.enqueue_now(F("G91"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ char buf[32]; // G1 X9999.99 F12345
+ unsigned int backup_speed = MMS_TO_MMM(feedrate_mm_s);
+ char sign[] = "\0";
+ int16_t value = movevalue / 100;
+ if (movevalue < 0) { value = -value; sign[0] = '-'; }
+ int16_t fraction = ABS(movevalue) % 100;
+ snprintf_P(buf, 32, PSTR("G0 %c%s%d.%02d F%d"), axiscode, sign, value, fraction, speed);
+ //DEBUG_ECHOPGM(" ", buf);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOLNPGM(" ✓ ");
+ if (backup_speed != speed) {
+ snprintf_P(buf, 32, PSTR("G0 F%d"), backup_speed);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOPGM(" ", buf);
+ }
+ // while (!enqueue_and_echo_command(buf)) idle();
+ //DEBUG_ECHOLNPGM(" ✓ ");
+ if (!old_relative_mode) {
+ //DEBUG_ECHOPGM("G90");
+ queue.enqueue_now(F("G90"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ }
+
+ ForceCompleteUpdate();
+ DEBUG_ECHOLNPGM("manmv done.");
+ return;
+
+ cannotmove:
+ DEBUG_ECHOLNPGM(" cannot move ", AS_CHAR(axiscode));
+ return;
+}
+
+#if HAS_PID_HEATING
+ void DGUSScreenHandler::HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t rawvalue = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("V1:", rawvalue);
+ float value = (float)rawvalue / 10;
+ DEBUG_ECHOLNPGM("V2:", value);
+ float newvalue = 0;
+
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_PID_P: newvalue = value; break;
+ case VP_E0_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E0_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_PID_P: newvalue = value; break;
+ case VP_E1_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E1_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HAS_HEATED_BED
+ case VP_BED_PID_P: newvalue = value; break;
+ case VP_BED_PID_I: newvalue = scalePID_i(value); break;
+ case VP_BED_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ }
+
+ DEBUG_ECHOLNPGM("V3:", newvalue);
+ *(float *)var.memadr = newvalue;
+
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ }
+#endif // HAS_PID_HEATING
+
+#if ENABLED(BABYSTEPPING)
+ void DGUSScreenHandler::HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleLiveAdjustZ");
+ int16_t flag = swap16(*(uint16_t*)val_ptr),
+ steps = flag ? -20 : 20;
+ ExtUI::smartAdjustAxis_steps(steps, ExtUI::axis_t::Z, true);
+ ForceCompleteUpdate();
+ }
+#endif
+
+#if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+
+ void DGUSScreenHandler::HandleFilamentOption(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleFilamentOption");
+
+ uint8_t e_temp = 0;
+ filament_data.heated = false;
+ uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
+ if (preheat_option <= 8) { // Load filament type
+ filament_data.action = 1;
+ }
+ else if (preheat_option >= 10) { // Unload filament type
+ preheat_option -= 10;
+ filament_data.action = 2;
+ filament_data.purge_length = DGUS_FILAMENT_PURGE_LENGTH;
+ }
+ else { // Cancel filament operation
+ filament_data.action = 0;
+ }
+
+ switch (preheat_option) {
+ case 0: // Load PLA
+ #ifdef PREHEAT_1_TEMP_HOTEND
+ e_temp = PREHEAT_1_TEMP_HOTEND;
+ #endif
+ break;
+ case 1: // Load ABS
+ TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND);
+ break;
+ case 2: // Load PET
+ #ifdef PREHEAT_3_TEMP_HOTEND
+ e_temp = PREHEAT_3_TEMP_HOTEND;
+ #endif
+ break;
+ case 3: // Load FLEX
+ #ifdef PREHEAT_4_TEMP_HOTEND
+ e_temp = PREHEAT_4_TEMP_HOTEND;
+ #endif
+ break;
+ case 9: // Cool down
+ default:
+ e_temp = 0;
+ break;
+ }
+
+ if (filament_data.action == 0) { // Go back to utility screen
+ #if HAS_HOTEND
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0);
+ #if HAS_MULTI_HOTEND
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1);
+ #endif
+ #endif
+ GotoScreen(DGUSLCD_SCREEN_UTILITY);
+ }
+ else { // Go to the preheat screen to show the heating progress
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E0;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E1;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ }
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_HEATING);
+ }
+ }
+
+ void DGUSScreenHandler::HandleFilamentLoadUnload(DGUS_VP_Variable &var) {
+ DEBUG_ECHOLNPGM("HandleFilamentLoadUnload");
+ if (filament_data.action <= 0) return;
+
+ // If we close to the target temperature, we can start load or unload the filament
+ if (thermalManager.hotEnoughToExtrude(filament_data.extruder) && \
+ thermalManager.targetHotEnoughToExtrude(filament_data.extruder)) {
+ float movevalue = DGUS_FILAMENT_LOAD_LENGTH_PER_TIME;
+
+ if (filament_data.action == 1) { // load filament
+ if (!filament_data.heated) {
+ //GotoScreen(DGUSLCD_SCREEN_FILAMENT_LOADING);
+ filament_data.heated = true;
+ }
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
+ }
+ else { // unload filament
+ if (!filament_data.heated) {
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_UNLOADING);
+ filament_data.heated = true;
+ }
+ // Before unloading extrude to prevent jamming
+ if (filament_data.purge_length >= 0) {
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
+ filament_data.purge_length -= movevalue;
+ }
+ else {
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue;
+ }
+ }
+ ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder);
+ }
+ }
+#endif // DGUS_FILAMENT_LOADUNLOAD
+
+bool DGUSScreenHandler::loop() {
+ dgusdisplay.loop();
+
+ const millis_t ms = millis();
+ static millis_t next_event_ms = 0;
+
+ if (!IsScreenComplete() || ELAPSED(ms, next_event_ms)) {
+ next_event_ms = ms + DGUS_UPDATE_INTERVAL_MS;
+ UpdateScreenVPData();
+ }
+
+ #if ENABLED(SHOW_BOOTSCREEN)
+ static bool booted = false;
+
+ if (!booted && TERN0(POWER_LOSS_RECOVERY, recovery.valid()))
+ booted = true;
+
+ if (!booted && ELAPSED(ms, BOOTSCREEN_TIMEOUT)) {
+ booted = true;
+ GotoScreen(TERN0(POWER_LOSS_RECOVERY, recovery.valid()) ? DGUSLCD_SCREEN_POWER_LOSS : DGUSLCD_SCREEN_MAIN);
+ }
+ #endif
+
+ return IsScreenComplete();
+}
+
+#endif // DGUS_LCD_UI_HIPRECY
diff --git a/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.h b/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.h
new file mode 100644
index 0000000..73e3527
--- /dev/null
+++ b/src/lcd/extui/dgus/hiprecy/DGUSScreenHandler.h
@@ -0,0 +1,31 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+#include "../DGUSScreenHandlerBase.h"
+
+typedef DGUSScreenHandler DGUSScreenHandlerClass;
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #define PLR_SCREEN_RECOVER DGUSLCD_SCREEN_SDPRINTMANIPULATION
+ #define PLR_SCREEN_CANCEL DGUSLCD_SCREEN_STATUS
+#endif
diff --git a/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp b/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp
new file mode 100644
index 0000000..86920d6
--- /dev/null
+++ b/src/lcd/extui/dgus/mks/DGUSDisplayDef.cpp
@@ -0,0 +1,802 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_MKS)
+
+#include "DGUSDisplayDef.h"
+#include "../DGUSDisplay.h"
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+
+#include "../../ui_api.h"
+#include "../../../marlinui.h"
+
+#if HAS_STEALTHCHOP
+ #include "../../../../module/stepper/trinamic.h"
+#endif
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ uint16_t distanceToMove = 10;
+#endif
+
+uint16_t manualMoveStep = 1;
+uint16_t distanceFilament = 10;
+uint16_t filamentSpeed_mm_s = 25;
+float ZOffset_distance = 0.1;
+float mesh_adj_distance = 0.01;
+float Z_distance = 0.1;
+
+//struct { uint16_t h, m, s; } dgus_time;
+
+//
+// Persistent settings
+//
+xy_int_t mks_corner_offsets[5]; // Initialized by settings.load()
+xyz_int_t mks_park_pos; // Initialized by settings.load()
+celsius_t mks_min_extrusion_temp; // Initialized by settings.load()
+
+void MKS_reset_settings() {
+ constexpr xy_int_t init_dgus_level_offsets[5] = {
+ { 20, 20 }, { 20, 20 },
+ { 20, 20 }, { 20, 20 },
+ { X_CENTER, Y_CENTER }
+ };
+ mks_language_index = MKS_SimpleChinese;
+ COPY(mks_corner_offsets, init_dgus_level_offsets);
+ mks_park_pos.set(20, 20, 10);
+ mks_min_extrusion_temp = 0;
+}
+
+xyz_pos_t position_before_pause;
+constexpr feedRate_t park_speed_xy = TERN(NOZZLE_PARK_FEATURE, NOZZLE_PARK_XY_FEEDRATE, 100),
+ park_speed_z = TERN(NOZZLE_PARK_FEATURE, NOZZLE_PARK_Z_FEEDRATE, 5);
+
+void MKS_pause_print_move() {
+ queue.exhaust();
+ position_before_pause = current_position;
+
+ // Save the current position, the raise amount, and 'already raised'
+ TERN_(POWER_LOSS_RECOVERY, if (recovery.enabled) recovery.save(true, mks_park_pos.z, true));
+
+ destination.z = _MIN(current_position.z + mks_park_pos.z, Z_MAX_POS);
+ prepare_internal_move_to_destination(park_speed_z);
+
+ destination.set(X_MIN_POS + mks_park_pos.x, Y_MIN_POS + mks_park_pos.y);
+ prepare_internal_move_to_destination(park_speed_xy);
+}
+
+void MKS_resume_print_move() {
+ destination.set(position_before_pause.x, position_before_pause.y);
+ prepare_internal_move_to_destination(park_speed_xy);
+ destination.z = position_before_pause.z;
+ prepare_internal_move_to_destination(park_speed_z);
+ TERN_(POWER_LOSS_RECOVERY, if (recovery.enabled) recovery.save(true));
+}
+
+float z_offset_add = 0;
+
+xyz_int_t tmc_step; // = { 0, 0, 0 }
+
+uint16_t lcd_default_light = 50;
+
+EX_FILAMENT_DEF ex_filament;
+RUNOUT_MKS_DEF runout_mks;
+NOZZLE_PARK_DEF nozzle_park_mks;
+
+const uint16_t VPList_Boot[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ 0x0000
+};
+
+#define MKSLIST_E_ITEM(N) VP_T_E##N##_Is, VP_T_E##N##_Set,
+
+const uint16_t VPList_Main[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded.
+ #if HAS_HOTEND
+ MKSLIST_E_ITEM(0) VP_E0_STATUS,
+ #if HAS_MULTI_HOTEND
+ MKSLIST_E_ITEM(1) VP_E1_STATUS,
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set, VP_BED_STATUS,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage, VP_FAN0_STATUS,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ #if ENABLED(LCD_SET_PROGRESS_MANUALLY)
+ VP_PrintProgress_Percentage,
+ #endif
+ 0x0000
+};
+
+const uint16_t MKSList_Home[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+ // Language
+ // VP_HOME_Dis,
+
+ 0x0000
+};
+
+const uint16_t MKSList_Setting[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+ // Language
+ VP_Setting_Dis,
+ 0x0000
+};
+
+const uint16_t MKSList_Tool[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+ // Language
+ VP_Tool_Dis,
+ // LCD BLK
+ VP_LCD_BLK,
+ 0x0000
+};
+
+const uint16_t MKSList_EXTRUE[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+
+ VP_Filament_distance,
+ VP_Filament_speed,
+
+ 0x0000
+};
+
+const uint16_t MKSList_LEVEL[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+
+ 0x0000
+};
+
+const uint16_t MKSList_MOVE[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+
+ 0x0000
+};
+
+const uint16_t MKSList_Print[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+ // Print Percent
+ VP_PrintProgress_Percentage,
+
+ VP_PrintTime,
+
+ VP_Flowrate_E0,
+ VP_Flowrate_E1,
+ VP_Feedrate_Percentage,
+
+ VP_PrintTime_H,
+ VP_PrintTime_M,
+ VP_PrintTime_S,
+
+ VP_XPos,
+ VP_YPos,
+ VP_ZPos,
+
+ 0x0000
+};
+
+const uint16_t MKSList_SD_File[] PROGMEM = {
+ VP_SD_FileName0, VP_SD_FileName1,
+ VP_SD_FileName2, VP_SD_FileName3,
+ VP_SD_FileName4, VP_SD_FileName5,
+ VP_SD_FileName6, VP_SD_FileName7,
+ VP_SD_FileName8, VP_SD_FileName9,
+
+ 0x0000
+};
+
+const uint16_t MKSList_TempOnly[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+ // LCD BLK
+ VP_LCD_BLK,
+ 0x0000
+};
+
+const uint16_t MKSList_Pluse[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+
+ // Pluse
+ VP_X_STEP_PER_MM,
+ VP_Y_STEP_PER_MM,
+ VP_Z_STEP_PER_MM,
+ VP_E0_STEP_PER_MM,
+ VP_E1_STEP_PER_MM,
+
+ 0x0000
+};
+
+const uint16_t MKSList_MaxSpeed[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+
+ // Pluse
+ VP_X_MAX_SPEED,
+ VP_Y_MAX_SPEED,
+ VP_Z_MAX_SPEED,
+ VP_E0_MAX_SPEED,
+ VP_E1_MAX_SPEED,
+
+ 0x0000
+};
+
+const uint16_t MKSList_MaxAcc[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+
+ // ACC
+ VP_ACC_SPEED,
+ VP_X_ACC_MAX_SPEED,
+ VP_Y_ACC_MAX_SPEED,
+ VP_Z_ACC_MAX_SPEED,
+ VP_E0_ACC_MAX_SPEED,
+ VP_E1_ACC_MAX_SPEED,
+
+ 0x0000
+};
+
+const uint16_t MKSList_PID[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+
+ // PID
+ VP_E0_PID_P,
+ VP_E0_PID_I,
+ VP_E0_PID_D,
+
+ 0x0000
+};
+
+const uint16_t MKSList_Level_Point[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ // FAN
+ VP_Fan0_Percentage,
+
+ // Level Point
+ VP_Level_Point_One_X,
+ VP_Level_Point_One_Y,
+ VP_Level_Point_Two_X,
+ VP_Level_Point_Two_Y,
+ VP_Level_Point_Three_X,
+ VP_Level_Point_Three_Y,
+ VP_Level_Point_Four_X,
+ VP_Level_Point_Four_Y,
+ VP_Level_Point_Five_X,
+ VP_Level_Point_Five_Y,
+
+ 0x0000
+};
+
+const uint16_t MKSList_Level_PrintConfig[] PROGMEM = {
+ VP_T_E0_Set,
+ VP_T_E1_Set,
+ VP_T_Bed_Set,
+ VP_Flowrate_E0,
+ VP_Flowrate_E1,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+
+ 0x0000
+};
+
+const uint16_t MKSList_PrintPauseConfig[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+
+ VP_X_PARK_POS,
+ VP_Y_PARK_POS,
+ VP_Z_PARK_POS,
+
+ 0x0000
+};
+
+const uint16_t MKSList_MotoConfig[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+
+ VP_TRAVEL_SPEED,
+ VP_FEEDRATE_MIN_SPEED,
+ VP_T_F_SPEED,
+
+ 0x0000
+};
+
+const uint16_t MKSList_EX_Config[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ VP_MIN_EX_T,VP_Min_EX_T_E,
+ 0x0000
+};
+
+const uint16_t MKSTMC_Config[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ // HB Temp
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ VP_MIN_EX_T,
+
+ VP_TMC_X_STEP,
+ VP_TMC_Y_STEP,
+ VP_TMC_Z_STEP,
+ VP_TMC_X1_Current,
+ VP_TMC_Y1_Current,
+ VP_TMC_X_Current,
+ VP_TMC_Y_Current,
+ VP_TMC_Z_Current,
+ VP_TMC_E0_Current,
+ VP_TMC_E1_Current,
+ VP_TMC_Z1_Current,
+
+ 0x0000
+};
+
+const uint16_t MKSAuto_Level[] PROGMEM = {
+ VP_MESH_LEVEL_POINT_DIS,
+ VP_ZPos,
+ 0x0000
+};
+
+const uint16_t MKSOffset_Config[] PROGMEM = {
+ // E Temp
+ REPEAT(EXTRUDERS, MKSLIST_E_ITEM)
+ VP_OFFSET_X,
+ VP_OFFSET_Y,
+ VP_OFFSET_Z,
+ 0x0000
+};
+
+const uint16_t MKSBabyStep[] PROGMEM = {
+ VP_ZOffset_DE_DIS,
+ 0x0000
+};
+
+const uint16_t MKSList_About[] PROGMEM = {
+ // Marlin version
+ VP_MARLIN_VERSION,
+ // H43 Version
+ VP_MKS_H43_VERSION,
+ VP_MKS_H43_UpdataVERSION,
+ 0x0000
+};
+
+// Page data updata
+const struct VPMapping VPMap[] PROGMEM = {
+ { MKSLCD_SCREEN_BOOT, VPList_Boot }, // Boot Page to show logo 0
+ { MKSLCD_SCREEN_HOME, MKSList_Home }, // Home, Page 1
+ { MKSLCD_SCREEN_SETTING, MKSList_Setting }, // Setting, Page 2
+ { MKSLCD_SCREEM_TOOL, MKSList_Tool }, // Page 3
+ { MKSLCD_SCREEN_EXTRUDE_P1, MKSList_EXTRUE }, // Page 4
+ { MKSLCD_SCREEN_EXTRUDE_P2, MKSList_EXTRUE }, // Page 11
+ { MKSLCD_PAUSE_SETTING_EX, MKSList_EXTRUE }, // Page 57
+ { MKSLCD_PAUSE_SETTING_EX2, MKSList_EXTRUE }, // Page 61
+ { MKSLCD_SCREEN_LEVEL, MKSList_LEVEL }, // Page 5
+ { MKSLCD_SCREEN_MOVE, MKSList_MOVE }, // Page 6
+ { MKSLCD_SCREEN_PRINT, MKSList_Print }, // Page 7
+ { MKSLCD_SCREEN_PAUSE, MKSList_Print }, // Page 26
+ { MKSLCD_SCREEN_CHOOSE_FILE, MKSList_SD_File }, // Page 15
+ { MKSLCD_SCREEN_MOTOR_PLUSE, MKSList_Pluse }, // Page 51
+ { MKSLCD_SCREEN_MOTOR_SPEED, MKSList_MaxSpeed }, // Page 55
+ { MKSLCD_SCREEN_MOTOR_ACC_MAX, MKSList_MaxAcc }, // Page 53
+ { MKSLCD_SCREEN_LEVEL_DATA, MKSList_Level_Point }, // Page 48
+ { MKSLCD_PrintPause_SET, MKSList_PrintPauseConfig }, // Page 49
+ { MKSLCD_FILAMENT_DATA, MKSList_SD_File }, // Page 50
+ { MKSLCD_SCREEN_Config, MKSList_TempOnly }, // Page 46
+ { MKSLCD_SCREEN_Config_MOTOR, MKSList_MotoConfig }, // Page 47
+ { MKSLCD_PID, MKSList_PID }, // Page 56
+ { MKSLCD_ABOUT, MKSList_About }, // Page 36
+ { MKSLCD_SCREEN_PRINT_CONFIG, MKSList_Level_PrintConfig }, // Page 60
+ { MKSLCD_SCREEN_EX_CONFIG, MKSList_EX_Config }, // Page 65
+ { MKSLCD_SCREEN_TMC_Config, MKSTMC_Config }, // Page 70
+ { MKSLCD_AUTO_LEVEL, MKSAuto_Level }, // Page 73
+ { MKSLCD_Screen_Offset_Config, MKSOffset_Config }, // Page 30
+ { MKSLCD_Screen_PMove, MKSList_MOVE }, // Page 64
+ { MKSLCD_Screen_Baby, MKSBabyStep }, // Page 71
+ //{ MKSLCD_SCREEN_LEVEL_DATA, MKSList_SD_File},
+ //{ MKSLCD_SCREEN_HOME, VPList_Boot },
+ { 0, nullptr } // List is terminated with an nullptr as table entry.
+};
+
+const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION;
+const char H43Version[] PROGMEM = "MKS H43_V1.30";
+const char Updata_Time[] PROGMEM = STRING_DISTRIBUTION_DATE;
+
+const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
+ // Helper to detect touch events
+ VPHELPER(VP_SCREENCHANGE, nullptr, ScreenHandler.ScreenChangeHook, nullptr),
+ VPHELPER(VP_SCREENCHANGE_ASK, nullptr, ScreenHandler.ScreenChangeHookIfIdle, nullptr),
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SCREENCHANGE_WHENSD, nullptr, ScreenHandler.ScreenChangeHookIfSD, nullptr),
+ #endif
+ VPHELPER(VP_CONFIRMED, nullptr, ScreenHandler.ScreenConfirmedOK, nullptr),
+
+ // Back Button
+ VPHELPER(VP_BACK_PAGE, nullptr, ScreenHandler.ScreenBackChange, nullptr),
+ VPHELPER(VP_TEMP_ALL_OFF, nullptr, ScreenHandler.HandleAllHeatersOff, nullptr),
+
+ VPHELPER(VP_MOVE_X, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, nullptr, ScreenHandler.HandleManualMove, nullptr),
+
+ VPHELPER(VP_X_HOME, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_Y_HOME, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_Z_HOME, nullptr, ScreenHandler.HandleManualMove, nullptr),
+
+ VPHELPER(VP_MOVE_DISTANCE, &manualMoveStep, ScreenHandler.GetManualMovestep, nullptr),
+
+ VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_LEVEL_POINT, nullptr, ScreenHandler.ManualAssistLeveling, nullptr),
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, ScreenHandler.HandlePowerLossRecovery, nullptr),
+ #endif
+ VPHELPER(VP_SETTINGS, nullptr, ScreenHandler.HandleSettings, nullptr),
+ #if ENABLED(SINGLE_Z_CALIBRATION)
+ VPHELPER(VP_Z_CALIBRATE, nullptr, ScreenHandler.HandleZCalibration, nullptr),
+ #endif
+ #if ENABLED(FIRST_LAYER_CAL)
+ VPHELPER(VP_Z_FIRST_LAYER_CAL, nullptr, ScreenHandler.HandleFirstLayerCal, nullptr),
+ #endif
+ {.VP = VP_MARLIN_VERSION, .memadr = (void *)MarlinVersion, .size = VP_MARLIN_VERSION_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM},
+ // M117 LCD String (We don't need the string in memory but "just" push it to the display on demand, hence the nullptr
+ {.VP = VP_M117, .memadr = nullptr, .size = VP_M117_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplay},
+ {.VP = VP_MKS_H43_VERSION, .memadr = (void *)H43Version, .size = VP_MKS_H43_VERSION_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM},
+ {.VP = VP_MKS_H43_UpdataVERSION, .memadr = (void *)Updata_Time, .size = VP_MKS_H43_VERSION_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM},
+
+ // Temperature Data
+ #if HAS_HOTEND
+ VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E0, &planner.flow_percentage[ExtUI::extruder_t::E0], ScreenHandler.HandleFlowRateChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_EPos, &destination.e, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_MOVE_E0, nullptr, ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E0_STATUS, &thermalManager.temp_hotend[0].target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(DGUS_PREHEAT_UI)
+ VPHELPER(VP_E0_BED_PREHEAT, nullptr, ScreenHandler.HandlePreheat, nullptr),
+ #endif
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_E0_PID_P, &thermalManager.temp_hotend[0].pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_I, &thermalManager.temp_hotend[0].pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_D, &thermalManager.temp_hotend[0].pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_E0, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ VPHELPER(VP_LOAD_Filament, nullptr, ScreenHandler.FilamentLoad, nullptr),
+ VPHELPER(VP_UNLOAD_Filament, nullptr, ScreenHandler.FilamentUnLoad, nullptr),
+ VPHELPER(VP_Filament_distance, &distanceFilament, ScreenHandler.GetManualFilament, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Filament_speed, &filamentSpeed_mm_s, ScreenHandler.GetManualFilamentSpeed, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #endif
+
+ #if HAS_MULTI_HOTEND
+ VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E1, &planner.flow_percentage[ExtUI::extruder_t::E1], ScreenHandler.HandleFlowRateChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_MOVE_E1, nullptr, ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ VPHELPER(VP_Filament_distance, &distanceFilament, ScreenHandler.GetManualFilament, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ VPHELPER(VP_Filament_speed, &filamentSpeed_mm_s, ScreenHandler.GetManualFilamentSpeed, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_PID_AUTOTUNE_E1, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+
+ VPHELPER(VP_E1_FILAMENT_LOAD_UNLOAD, nullptr, ScreenHandler.HandleFilamentOption, ScreenHandler.HandleFilamentLoadUnload),
+ #endif
+
+ #if HAS_HEATED_BED
+ VPHELPER(VP_T_Bed_Is, &thermalManager.temp_bed.celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_Bed_Set, &thermalManager.temp_bed.target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_BED_CONTROL, &thermalManager.temp_bed.target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_BED_STATUS, &thermalManager.temp_bed.target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMPBED)
+ VPHELPER(VP_BED_PID_P, &thermalManager.temp_bed.pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_I, &thermalManager.temp_bed.pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_D, &thermalManager.temp_bed.pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_BED, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #endif
+
+ // Fan Data
+ #if HAS_FAN
+ #define FAN_VPHELPER(N) \
+ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], ScreenHandler.DGUSLCD_SetUint8, ScreenHandler.DGUSLCD_SendFanToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], ScreenHandler.HandleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, ScreenHandler.DGUSLCD_SendFanStatusToDisplay),
+ REPEAT(FAN_COUNT, FAN_VPHELPER)
+ #endif
+
+ // Feedrate
+ VPHELPER(VP_Feedrate_Percentage, &feedrate_percentage, ScreenHandler.DGUSLCD_SetValueDirectly, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+
+ // Position Data
+ VPHELPER(VP_XPos, ¤t_position.x, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_YPos, ¤t_position.y, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_ZPos, ¤t_position.z, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+
+ // Level Point Set
+ VPHELPER(VP_Level_Point_One_X, &mks_corner_offsets[0].x, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Level_Point_One_Y, &mks_corner_offsets[0].y, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Level_Point_Two_X, &mks_corner_offsets[1].x, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Level_Point_Two_Y, &mks_corner_offsets[1].y, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Level_Point_Three_X, &mks_corner_offsets[2].x, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Level_Point_Three_Y, &mks_corner_offsets[2].y, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Level_Point_Four_X, &mks_corner_offsets[3].x, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Level_Point_Four_Y, &mks_corner_offsets[3].y, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Level_Point_Five_X, &mks_corner_offsets[4].x, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Level_Point_Five_Y, &mks_corner_offsets[4].y, ScreenHandler.HandleChangeLevelPoint, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+
+ // Print Progress
+ VPHELPER(VP_PrintProgress_Percentage, nullptr, nullptr, ScreenHandler.DGUSLCD_SendPrintProgressToDisplay),
+
+ // LCD Control
+ VPHELPER(VP_LCD_BLK, &lcd_default_light, ScreenHandler.LCD_BLK_Adjust, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+
+ // SD File - Back
+ VPHELPER(VP_SD_FileSelect_Back, nullptr, ScreenHandler.SD_FileBack, nullptr),
+
+ // Print Time
+ VPHELPER_STR(VP_PrintTime, nullptr, VP_PrintTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeToDisplay),
+
+ #if ENABLED(PRINTCOUNTER)
+ VPHELPER_STR(VP_PrintAccTime, nullptr, VP_PrintAccTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintAccTimeToDisplay),
+ VPHELPER_STR(VP_PrintsTotal, nullptr, VP_PrintsTotal_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintsTotalToDisplay),
+ #endif
+
+ VPHELPER(VP_X_STEP_PER_MM, &planner.settings.axis_steps_per_mm[X_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ VPHELPER(VP_Y_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Y_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ VPHELPER(VP_Z_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Z_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+
+ VPHELPER(VP_X_MAX_SPEED, &planner.settings.max_feedrate_mm_s[X_AXIS], ScreenHandler.HandleMaxSpeedChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ VPHELPER(VP_Y_MAX_SPEED, &planner.settings.max_feedrate_mm_s[Y_AXIS], ScreenHandler.HandleMaxSpeedChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ VPHELPER(VP_Z_MAX_SPEED, &planner.settings.max_feedrate_mm_s[Z_AXIS], ScreenHandler.HandleMaxSpeedChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+
+ #if HAS_HOTEND
+ VPHELPER(VP_E0_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(0)], ScreenHandler.HandleExtruderMaxSpeedChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ #if HAS_MULTI_HOTEND
+ VPHELPER(VP_E1_MAX_SPEED, &planner.settings.max_feedrate_mm_s[E_AXIS_N(1)], ScreenHandler.HandleExtruderMaxSpeedChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ #endif
+ #endif
+
+ VPHELPER(VP_X_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[X_AXIS], ScreenHandler.HandleMaxAccChange, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Y_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[Y_AXIS], ScreenHandler.HandleMaxAccChange, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Z_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[Z_AXIS], ScreenHandler.HandleMaxAccChange, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+
+ #if HAS_HOTEND
+ VPHELPER(VP_E0_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(0)], ScreenHandler.HandleExtruderAccChange, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #if HAS_MULTI_HOTEND
+ VPHELPER(VP_E1_ACC_MAX_SPEED, (uint16_t *)&planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)], ScreenHandler.HandleExtruderAccChange, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #endif
+
+ VPHELPER(VP_TRAVEL_SPEED, (uint16_t *)&planner.settings.travel_acceleration, ScreenHandler.HandleTravelAccChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ VPHELPER(VP_FEEDRATE_MIN_SPEED, (uint16_t *)&planner.settings.min_feedrate_mm_s, ScreenHandler.HandleFeedRateMinChange, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ VPHELPER(VP_T_F_SPEED, (uint16_t *)&planner.settings.min_travel_feedrate_mm_s, ScreenHandler.HandleMin_T_F, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ VPHELPER(VP_ACC_SPEED, (uint16_t *)&planner.settings.acceleration, ScreenHandler.HandleAccChange, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+
+ VPHELPER(VP_X_PARK_POS, &mks_park_pos.x, ScreenHandler.GetParkPos, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Y_PARK_POS, &mks_park_pos.y, ScreenHandler.GetParkPos, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Z_PARK_POS, &mks_park_pos.z, ScreenHandler.GetParkPos, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+
+ #if ENABLED(PREVENT_COLD_EXTRUSION)
+ VPHELPER(VP_MIN_EX_T, &thermalManager.extrude_min_temp, ScreenHandler.HandleGetExMinTemp, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+
+ #if ENABLED(SENSORLESS_HOMING) // TMC SENSORLESS Setting
+ #if X_HAS_STEALTHCHOP
+ VPHELPER(VP_TMC_X_STEP, &tmc_step.x, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendTMCStepValue),
+ #endif
+ #if Y_HAS_STEALTHCHOP
+ VPHELPER(VP_TMC_Y_STEP, &tmc_step.y, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendTMCStepValue),
+ #endif
+ #if Z_HAS_STEALTHCHOP
+ VPHELPER(VP_TMC_Z_STEP, &tmc_step.z, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendTMCStepValue),
+ #endif
+ #endif
+
+ #if HAS_TRINAMIC_CONFIG // TMC Current Setting
+ #if AXIS_IS_TMC(X)
+ VPHELPER(VP_TMC_X_Current, &stepperX.val_mA, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #if AXIS_IS_TMC(Y)
+ VPHELPER(VP_TMC_Y_Current, &stepperY.val_mA, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #if AXIS_IS_TMC(Z)
+ VPHELPER(VP_TMC_Z_Current, &stepperZ.val_mA, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #if AXIS_IS_TMC(E0)
+ VPHELPER(VP_TMC_E0_Current, &stepperE0.val_mA, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #if AXIS_IS_TMC(E1)
+ VPHELPER(VP_TMC_E1_Current, &stepperE1.val_mA, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #if AXIS_IS_TMC(X2)
+ VPHELPER(VP_TMC_X1_Current, &stepperX2.val_mA, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #if AXIS_IS_TMC(Y2)
+ VPHELPER(VP_TMC_Y1_Current, &stepperY2.val_mA, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #if AXIS_IS_TMC(Z2)
+ VPHELPER(VP_TMC_Z1_Current, &stepperZ2.val_mA, ScreenHandler.TMC_ChangeConfig, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+ #endif
+
+ VPHELPER(VP_EEPROM_CTRL, nullptr, ScreenHandler.EEPROM_CTRL, nullptr),
+ VPHELPER(VP_LEVEL_BUTTON, nullptr, ScreenHandler.Level_Ctrl, nullptr),
+ VPHELPER(VP_LANGUAGE_CHANGE, nullptr, ScreenHandler.LanguageChange, nullptr),
+
+ //VPHELPER(VP_SD_Print_LiveAdjustZ, nullptr, ScreenHandler.HandleLiveAdjustZ, nullptr),
+
+ VPHELPER(VP_SD_Print_LiveAdjustZ_Confirm, nullptr, ScreenHandler.ZoffsetConfirm, nullptr),
+
+ VPHELPER(VP_ZOffset_Distance,nullptr ,ScreenHandler.GetZoffsetDistance, nullptr),
+ VPHELPER(VP_MESH_LEVEL_ADJUST, nullptr, ScreenHandler.MeshLevelDistanceConfig, nullptr),
+ VPHELPER(VP_MESH_LEVEL_POINT,nullptr, ScreenHandler.MeshLevel,nullptr),
+
+ #if ENABLED(PREVENT_COLD_EXTRUSION)
+ VPHELPER(VP_Min_EX_T_E, &thermalManager.extrude_min_temp, ScreenHandler.GetMinExtrudeTemp, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ #endif
+
+ VPHELPER(VP_AutoTurnOffSw, nullptr, ScreenHandler.GetTurnOffCtrl, nullptr),
+
+ #if HAS_HOTEND
+ VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ #if HAS_MULTI_HOTEND
+ VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<0>),
+ #endif
+ #endif
+
+ // SDCard File listing
+
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SD_FileSelected, nullptr, ScreenHandler.DGUSLCD_SD_FileSelected, nullptr),
+ VPHELPER(VP_SD_ScrollEvent, nullptr, ScreenHandler.DGUSLCD_SD_ScrollFilelist, nullptr),
+ VPHELPER(VP_SD_FileSelectConfirm, nullptr, ScreenHandler.DGUSLCD_SD_StartPrint, nullptr),
+ VPHELPER_STR(VP_SD_FileName0, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName1, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName2, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName3, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName4, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName5, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName6, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName7, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName8, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName9, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER(VP_SD_ResumePauseAbort, nullptr, ScreenHandler.DGUSLCD_SD_ResumePauseAbort, nullptr),
+ VPHELPER(VP_SD_AbortPrintConfirmed, nullptr, ScreenHandler.DGUSLCD_SD_ReallyAbort, nullptr),
+ VPHELPER(VP_SD_Print_Setting, nullptr, ScreenHandler.DGUSLCD_SD_PrintTune, nullptr),
+ #if ENABLED(BABYSTEPPING)
+ VPHELPER(VP_SD_Print_LiveAdjustZ, nullptr, ScreenHandler.HandleLiveAdjustZ, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<2>),
+ VPHELPER(VP_ZOffset_DE_DIS, &z_offset_add, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ #endif
+ #if HAS_BED_PROBE
+ VPHELPER(VP_OFFSET_X, &probe.offset.x, ScreenHandler.GetOffsetValue,ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_OFFSET_Y, &probe.offset.y, ScreenHandler.GetOffsetValue,ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_OFFSET_Z, &probe.offset.z, ScreenHandler.GetOffsetValue,ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ #endif
+ #else
+ VPHELPER(VP_SD_FileSelected, nullptr, ScreenHandler.PrintReturn, nullptr),
+ #endif
+
+ #if ENABLED(DGUS_UI_WAITING)
+ VPHELPER(VP_WAITING_STATUS, nullptr, nullptr, ScreenHandler.DGUSLCD_SendWaitingStatusToDisplay),
+ #endif
+
+ // Messages for the User, shared by the popup and the kill screen. They can't be autouploaded as we do not buffer content.
+ //{.VP = VP_MSGSTR1, .memadr = nullptr, .size = VP_MSGSTR1_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM},
+ //{.VP = VP_MSGSTR2, .memadr = nullptr, .size = VP_MSGSTR2_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM},
+ //{.VP = VP_MSGSTR3, .memadr = nullptr, .size = VP_MSGSTR3_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM},
+ //{.VP = VP_MSGSTR4, .memadr = nullptr, .size = VP_MSGSTR4_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM},
+
+ {.VP = VP_MSGSTR1, .memadr = nullptr, .size = VP_MSGSTR1_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplay_Language},
+ {.VP = VP_MSGSTR2, .memadr = nullptr, .size = VP_MSGSTR2_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplay_Language},
+ {.VP = VP_MSGSTR3, .memadr = nullptr, .size = VP_MSGSTR3_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplay_Language},
+ {.VP = VP_MSGSTR4, .memadr = nullptr, .size = VP_MSGSTR4_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplay_Language},
+
+ VPHELPER(0, 0, 0, 0) // must be last entry.
+};
+
+#endif // DGUS_LCD_UI_MKS
diff --git a/src/lcd/extui/dgus/mks/DGUSDisplayDef.h b/src/lcd/extui/dgus/mks/DGUSDisplayDef.h
new file mode 100644
index 0000000..bdcd248
--- /dev/null
+++ b/src/lcd/extui/dgus/mks/DGUSDisplayDef.h
@@ -0,0 +1,712 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+#include "../DGUSDisplayDef.h"
+
+//#define DGUS_MKS_RUNOUT_SENSOR
+
+#define LOGO_TIME_DELAY TERN(USE_MKS_GREEN_UI, 8000, 1500)
+
+#if ENABLED(DGUS_MKS_RUNOUT_SENSOR)
+ #define MT_DET_1_PIN 1
+ #define MT_DET_2_PIN 2
+ #define MT_DET_PIN_STATE LOW
+#endif
+
+#define MKS_FINSH
+
+extern uint16_t manualMoveStep;
+extern uint16_t distanceFilament;
+extern uint16_t filamentSpeed_mm_s;
+extern float ZOffset_distance;
+extern float mesh_adj_distance;
+extern float Z_distance;
+
+//extern struct { uint16_t h, m, s; } dgus_time;
+
+extern xy_int_t mks_corner_offsets[5];
+extern xyz_int_t mks_park_pos;
+extern celsius_t mks_min_extrusion_temp;
+
+void MKS_reset_settings(); // Restore persistent settings to defaults
+
+void MKS_pause_print_move();
+void MKS_resume_print_move();
+
+extern float z_offset_add;
+
+extern xyz_int_t tmc_step;
+
+extern uint16_t lcd_default_light;
+
+#if X_HAS_STEALTHCHOP
+ extern uint16_t tmc_x_current;
+#endif
+#if Y_HAS_STEALTHCHOP
+ extern uint16_t tmc_y_current;
+#endif
+#if Z_HAS_STEALTHCHOP
+ extern uint16_t tmc_z_current;
+#endif
+#if E0_HAS_STEALTHCHOP
+ extern uint16_t tmc_e0_current;
+#endif
+#if E1_HAS_STEALTHCHOP
+ extern uint16_t tmc_e1_current;
+#endif
+
+typedef enum {
+ EX_HEATING,
+ EX_HEAT_STARUS,
+ EX_CHANGING,
+ EX_CHANGE_STATUS,
+ EX_NONE,
+} EX_STATUS_DEF;
+
+typedef struct {
+ //uint8_t ex_change_flag:1;
+ //uint8_t ex_heat_flag:1;
+ uint8_t ex_load_unload_flag:1; //0:unload 1:load
+ EX_STATUS_DEF ex_status;
+ uint32_t ex_tick_start;
+ uint32_t ex_tick_end;
+ uint32_t ex_speed;
+ uint32_t ex_length;
+ uint32_t ex_need_time;
+} EX_FILAMENT_DEF;
+
+extern EX_FILAMENT_DEF ex_filament;
+
+typedef enum {
+ UNRUNOUT_STATUS,
+ RUNOUT_STATUS,
+ RUNOUT_WAITING_STATUS,
+ RUNOUT_BEGIN_STATUS,
+} RUNOUT_MKS_STATUS_DEF;
+
+typedef struct {
+ RUNOUT_MKS_STATUS_DEF runout_status;
+ uint8_t pin_status;
+ uint8_t de_count;
+ uint8_t de_times;
+} RUNOUT_MKS_DEF;
+
+extern RUNOUT_MKS_DEF runout_mks;
+
+typedef struct {
+ uint8_t print_pause_start_flag:1;
+ uint8_t runout_flag:1;
+ bool blstatus;
+ uint16_t x_pos;
+ uint16_t y_pos;
+ uint16_t z_pos;
+} NOZZLE_PARK_DEF;
+
+extern NOZZLE_PARK_DEF nozzle_park_mks;
+
+enum DGUSLCD_Screens : uint8_t {
+ #if ENABLED(USE_MKS_GREEN_UI)
+
+ DGUSLCD_SCREEN_BOOT = 33,
+ DGUSLCD_SCREEN_MAIN = 60,
+ DGUSLCD_SCREEN_STATUS = 60,
+ DGUSLCD_SCREEN_STATUS2 = 60,
+ DGUSLCD_SCREEN_PREHEAT = 18,
+ DGUSLCD_SCREEN_POWER_LOSS = 100,
+ DGUSLCD_SCREEN_MANUALMOVE = 192,
+ DGUSLCD_SCREEN_UTILITY = 120,
+ DGUSLCD_SCREEN_FILAMENT_UNLOADING = 158,
+ DGUSLCD_SCREEN_SDFILELIST = 15,
+ DGUSLCD_SCREEN_SDPRINTMANIPULATION = 15,
+ DGUSLCD_SCREEN_SDPRINTTUNE = 17,
+
+ MKSLCD_SCREEN_BOOT = 33,
+ MKSLCD_SCREEN_HOME = 60, // MKS main page
+ MKSLCD_SCREEN_SETTING = 62, // MKS Setting page / no wifi whit
+ MKSLCD_SCREEM_TOOL = 64, // MKS Tool page
+ MKSLCD_SCREEN_EXTRUDE_P1 = 75,
+ MKSLCD_SCREEN_EXTRUDE_P2 = 77,
+ MKSLCD_SCREEN_LEVEL = 73,
+ MKSLCD_AUTO_LEVEL = 81,
+ MKSLCD_SCREEN_MOVE = 66,
+ MKSLCD_SCREEN_PRINT = 68,
+ MKSLCD_SCREEN_PAUSE = 70,
+ MKSLCD_SCREEN_CHOOSE_FILE = 87,
+ MKSLCD_SCREEN_NO_CHOOSE_FILE = 88,
+ MKSLCD_SCREEN_Config = 101,
+ MKSLCD_SCREEN_Config_MOTOR = 103,
+ MKSLCD_SCREEN_MOTOR_PLUSE = 104,
+ MKSLCD_SCREEN_MOTOR_SPEED = 102,
+ MKSLCD_SCREEN_MOTOR_ACC_MAX = 105,
+ MKSLCD_SCREEN_PRINT_CONFIG = 72,
+ MKSLCD_SCREEN_LEVEL_DATA = 106,
+ MKSLCD_PrintPause_SET = 107,
+ MKSLCD_FILAMENT_DATA = 50,
+ MKSLCD_ABOUT = 83,
+ MKSLCD_PID = 108,
+ MKSLCD_PAUSE_SETTING_MOVE = 98,
+ MKSLCD_PAUSE_SETTING_EX = 96,
+ MKSLCD_PAUSE_SETTING_EX2 = 97,
+ MKSLCD_SCREEN_PRINT_CONFIRM = 94,
+ MKSLCD_SCREEN_EX_CONFIG = 112,
+ MKSLCD_SCREEN_EEP_Config = 89,
+ MKSLCD_SCREEN_PrintDone = 92,
+ MKSLCD_SCREEN_TMC_Config = 111,
+ MKSLCD_Screen_Offset_Config = 109,
+ MKSLCD_Screen_PMove = 98,
+ MKSLCD_Screen_Baby = 79,
+
+ #else
+
+ DGUSLCD_SCREEN_BOOT = 120,
+ DGUSLCD_SCREEN_MAIN = 1,
+
+ DGUSLCD_SCREEN_STATUS = 1,
+ DGUSLCD_SCREEN_STATUS2 = 1,
+ DGUSLCD_SCREEN_PREHEAT = 18,
+ DGUSLCD_SCREEN_POWER_LOSS = 100,
+ DGUSLCD_SCREEN_MANUALMOVE = 192,
+ DGUSLCD_SCREEN_UTILITY = 120,
+ DGUSLCD_SCREEN_FILAMENT_UNLOADING = 158,
+ DGUSLCD_SCREEN_SDFILELIST = 15,
+ DGUSLCD_SCREEN_SDPRINTMANIPULATION = 15,
+ DGUSLCD_SCREEN_SDPRINTTUNE = 17,
+
+ MKSLCD_SCREEN_BOOT = 0,
+ MKSLCD_SCREEN_HOME = 1, // MKS main page
+ MKSLCD_SCREEN_SETTING = 2, // MKS Setting page / no wifi whit
+ MKSLCD_SCREEM_TOOL = 3, // MKS Tool page
+ MKSLCD_SCREEN_EXTRUDE_P1 = 4,
+ MKSLCD_SCREEN_EXTRUDE_P2 = 11,
+ MKSLCD_SCREEN_LEVEL = 5,
+ MKSLCD_AUTO_LEVEL = 73,
+ MKSLCD_SCREEN_LEVEL_PRESS = 9,
+ MKSLCD_SCREEN_MOVE = 6,
+ MKSLCD_SCREEN_PRINT = 7,
+ MKSLCD_SCREEN_PRINT_PRESS = 13,
+ MKSLCD_SCREEN_PAUSE = 26,
+ MKSLCD_SCREEN_PAUSE_PRESS = 26,
+ MKSLCD_SCREEN_CHOOSE_FILE = 15,
+ MKSLCD_SCREEN_NO_CHOOSE_FILE = 17,
+ MKSLCD_SCREEN_Config = 46,
+ MKSLCD_SCREEN_Config_MOTOR = 47,
+ MKSLCD_SCREEN_MOTOR_PLUSE = 51,
+ MKSLCD_SCREEN_MOTOR_SPEED = 55,
+ MKSLCD_SCREEN_MOTOR_ACC_MAX = 53,
+ MKSLCD_SCREEN_PRINT_CONFIG = 60,
+ MKSLCD_SCREEN_LEVEL_DATA = 48,
+ MKSLCD_PrintPause_SET = 49,
+ MKSLCD_FILAMENT_DATA = 50,
+ MKSLCD_ABOUT = 36,
+ MKSLCD_PID = 56,
+ MKSLCD_PAUSE_SETTING_MOVE = 58,
+ MKSLCD_PAUSE_SETTING_EX = 57,
+ MKSLCD_PAUSE_SETTING_EX2 = 61,
+ MKSLCD_SCREEN_NO_FILE = 42,
+ MKSLCD_SCREEN_PRINT_CONFIRM = 43,
+ MKSLCD_SCREEN_EX_CONFIG = 65,
+ MKSLCD_SCREEN_EEP_Config = 20,
+ MKSLCD_SCREEN_PrintDone = 25,
+ MKSLCD_SCREEN_TMC_Config = 70,
+ MKSLCD_Screen_Offset_Config = 30,
+ MKSLCD_Screen_PMove = 64,
+ MKSLCD_Screen_Baby = 71,
+
+ #endif
+
+ DGUSLCD_SCREEN_CONFIRM = 240,
+ DGUSLCD_SCREEN_KILL = 250, ///< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version")
+ DGUSLCD_SCREEN_WAITING = 251,
+ DGUSLCD_SCREEN_POPUP = 252, ///< special target, popup screen will also return this code to say "return to previous screen"
+ DGUSLCD_SCREEN_UNUSED = 255
+};
+
+
+// Place for status messages.
+constexpr uint16_t VP_M117 = 0x7020;
+constexpr uint8_t VP_M117_LEN = 0x20;
+
+// Heater status
+constexpr uint16_t VP_E0_STATUS = 0x3410;
+constexpr uint16_t VP_E1_STATUS = 0x3412;
+//constexpr uint16_t VP_E2_STATUS = 0x3414;
+//constexpr uint16_t VP_E3_STATUS = 0x3416;
+//constexpr uint16_t VP_E4_STATUS = 0x3418;
+//constexpr uint16_t VP_E5_STATUS = 0x341A;
+constexpr uint16_t VP_MOVE_OPTION = 0x3500;
+
+// // PIDs
+// constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , 2 byte unsigned int , 0~1638.4
+// constexpr uint16_t VP_E0_PID_I = 0x3702;
+// constexpr uint16_t VP_E0_PID_D = 0x3704;
+// constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment , 2 byte unsigned int , 0~1638.4
+// constexpr uint16_t VP_E1_PID_I = 0x3708;
+// constexpr uint16_t VP_E1_PID_D = 0x370A;
+// constexpr uint16_t VP_BED_PID_P = 0x3710;
+// constexpr uint16_t VP_BED_PID_I = 0x3712;
+// constexpr uint16_t VP_BED_PID_D = 0x3714;
+
+// Waiting screen status
+constexpr uint16_t VP_WAITING_STATUS = 0x3800;
+
+// SPs for certain variables...
+// located at 0x5000 and up
+// Not used yet!
+// This can be used e.g to make controls / data display invisible
+constexpr uint16_t SP_T_E0_Is = 0x5000;
+constexpr uint16_t SP_T_E0_Set = 0x5010;
+constexpr uint16_t SP_T_E1_Is = 0x5020;
+constexpr uint16_t SP_T_Bed_Is = 0x5030;
+constexpr uint16_t SP_T_Bed_Set = 0x5040;
+
+/*************************************************************************************************************************
+ *************************************************************************************************************************
+ * DGUS for MKS Mem layout
+ ************************************************************************************************************************
+ ************************************************************************************************************************/
+
+#if ENABLED(MKS_FINSH)
+ /* -------------------------------0x1000-0x1FFF------------------------------- */
+ constexpr uint16_t VP_MSGSTR1 = 0x1100;
+ constexpr uint8_t VP_MSGSTR1_LEN = 0x20; // might be more place for it...
+ constexpr uint16_t VP_MSGSTR2 = 0x1140;
+ constexpr uint8_t VP_MSGSTR2_LEN = 0x20;
+ constexpr uint16_t VP_MSGSTR3 = 0x1180;
+ constexpr uint8_t VP_MSGSTR3_LEN = 0x20;
+ constexpr uint16_t VP_MSGSTR4 = 0x11C0;
+ constexpr uint8_t VP_MSGSTR4_LEN = 0x20;
+
+ constexpr uint16_t VP_MARLIN_VERSION = 0x1A00;
+ constexpr uint8_t VP_MARLIN_VERSION_LEN = 16; // there is more space on the display, if needed.
+
+
+ constexpr uint16_t VP_SCREENCHANGE_ASK = 0x1500;
+ constexpr uint16_t VP_SCREENCHANGE = 0x1501; // Key-Return button to new menu pressed. Data contains target screen in low byte and info in high byte.
+ constexpr uint16_t VP_TEMP_ALL_OFF = 0x1502; // Turn all heaters off. Value arbitrary ;)=
+ constexpr uint16_t VP_SCREENCHANGE_WHENSD = 0x1503; // "Print" Button touched -- go only there if there is an SD Card.
+ constexpr uint16_t VP_CONFIRMED = 0x1510; // OK on confirm screen.
+
+ constexpr uint16_t VP_BACK_PAGE = 0x1600;
+ constexpr uint16_t VP_SETTINGS = 0x1620;
+ // Power loss recovery
+ constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x1680;
+ /* -------------------------------0x2000-0x2FFF------------------------------- */
+ // Temperatures.
+ constexpr uint16_t VP_T_E0_Is = 0x2000; // 4 Byte Integer
+ constexpr uint16_t VP_T_E0_Set = 0x2004; // 2 Byte Integer
+ constexpr uint16_t VP_T_E1_Is = 0x2008; // 4 Byte Integer
+ constexpr uint16_t VP_T_E1_Set = 0x200B; // 2 Byte Integer
+ constexpr uint16_t VP_T_E2_Is = 0x2010; // 4 Byte Integer
+ constexpr uint16_t VP_T_E2_Set = 0x2014; // 2 Byte Integer
+ constexpr uint16_t VP_T_E3_Is = 0x2018; // 4 Byte Integer
+ constexpr uint16_t VP_T_E3_Set = 0x201B; // 2 Byte Integer
+ constexpr uint16_t VP_T_E4_Is = 0x2020; // 4 Byte Integer
+ constexpr uint16_t VP_T_E4_Set = 0x2024; // 2 Byte Integer
+ constexpr uint16_t VP_T_E5_Is = 0x2028; // 4 Byte Integer
+ constexpr uint16_t VP_T_E5_Set = 0x202B; // 2 Byte Integer
+ constexpr uint16_t VP_T_E6_Is = 0x2030; // 4 Byte Integer
+ constexpr uint16_t VP_T_E6_Set = 0x2034; // 2 Byte Integer
+ constexpr uint16_t VP_T_E7_Is = 0x2038; // 4 Byte Integer
+ constexpr uint16_t VP_T_E7_Set = 0x203B; // 2 Byte Integer
+
+ constexpr uint16_t VP_T_Bed_Is = 0x2040; // 4 Byte Integer
+ constexpr uint16_t VP_T_Bed_Set = 0x2044; // 2 Byte Integer
+
+ constexpr uint16_t VP_Min_EX_T_E = 0x2100;
+
+ constexpr uint16_t VP_Flowrate_E0 = 0x2200; // 2 Byte Integer
+ constexpr uint16_t VP_Flowrate_E1 = 0x2202; // 2 Byte Integer
+ constexpr uint16_t VP_Flowrate_E2 = 0x2204;
+ constexpr uint16_t VP_Flowrate_E3 = 0x2206;
+ constexpr uint16_t VP_Flowrate_E4 = 0x2208;
+ constexpr uint16_t VP_Flowrate_E5 = 0x220A;
+ constexpr uint16_t VP_Flowrate_E6 = 0x220C;
+ constexpr uint16_t VP_Flowrate_E7 = 0x220E;
+
+ // Move
+ constexpr uint16_t VP_MOVE_X = 0x2300;
+ constexpr uint16_t VP_MOVE_Y = 0x2302;
+ constexpr uint16_t VP_MOVE_Z = 0x2304;
+ constexpr uint16_t VP_MOVE_E0 = 0x2310;
+ constexpr uint16_t VP_MOVE_E1 = 0x2312;
+ constexpr uint16_t VP_MOVE_E2 = 0x2314;
+ constexpr uint16_t VP_MOVE_E3 = 0x2316;
+ constexpr uint16_t VP_MOVE_E4 = 0x2318;
+ constexpr uint16_t VP_MOVE_E5 = 0x231A;
+ constexpr uint16_t VP_MOVE_E6 = 0x231C;
+ constexpr uint16_t VP_MOVE_E7 = 0x231E;
+ constexpr uint16_t VP_HOME_ALL = 0x2320;
+ constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2330;
+ constexpr uint16_t VP_MOVE_DISTANCE = 0x2334;
+ constexpr uint16_t VP_X_HOME = 0x2336;
+ constexpr uint16_t VP_Y_HOME = 0x2338;
+ constexpr uint16_t VP_Z_HOME = 0x233A;
+
+ // Fan Control Buttons , switch between "off" and "on"
+ constexpr uint16_t VP_FAN0_CONTROL = 0x2350;
+ constexpr uint16_t VP_FAN1_CONTROL = 0x2352;
+ constexpr uint16_t VP_FAN2_CONTROL = 0x2354;
+ constexpr uint16_t VP_FAN3_CONTROL = 0x2356;
+ constexpr uint16_t VP_FAN4_CONTROL = 0x2358;
+ constexpr uint16_t VP_FAN5_CONTROL = 0x235A;
+
+ constexpr uint16_t VP_LANGUAGE_CHANGE = 0x2380;
+ constexpr uint16_t VP_LANGUAGE_CHANGE1 = 0x2382;
+ constexpr uint16_t VP_LANGUAGE_CHANGE2 = 0x2384;
+ constexpr uint16_t VP_LANGUAGE_CHANGE3 = 0x2386;
+ constexpr uint16_t VP_LANGUAGE_CHANGE4 = 0x2388;
+ constexpr uint16_t VP_LANGUAGE_CHANGE5 = 0x238A;
+
+ // LEVEL
+ constexpr uint16_t VP_LEVEL_POINT = 0x2400;
+ constexpr uint16_t VP_MESH_LEVEL_POINT = 0x2410;
+ constexpr uint16_t VP_MESH_LEVEL_ADJUST = 0x2412;
+ constexpr uint16_t VP_MESH_LEVEL_DIP = 0x2414;
+ constexpr uint16_t VP_MESH_LEVEL_POINT_X = 0x2416;
+ constexpr uint16_t VP_MESH_LEVEL_POINT_Y = 0x2418;
+ constexpr uint16_t VP_LEVEL_BUTTON = 0x2420;
+ constexpr uint16_t VP_MESH_LEVEL_POINT_DIS = 0x2422;
+ constexpr uint16_t VP_MESH_LEVEL_BACK = 0x2424;
+
+ constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2500;
+ constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x2504;
+ constexpr uint16_t VP_LOAD_Filament = 0x2508;
+ // constexpr uint16_t VP_LOAD_UNLOAD_Cancle = 0x250A;
+ constexpr uint16_t VP_UNLOAD_Filament = 0x250B;
+ constexpr uint16_t VP_Filament_distance = 0x2600;
+ constexpr uint16_t VP_Filament_speed = 0x2604;
+ constexpr uint16_t VP_MIN_EX_T = 0x2606;
+
+ constexpr uint16_t VP_E1_Filament_distance = 0x2614;
+ constexpr uint16_t VP_E1_Filament_speed = 0x2616;
+ constexpr uint16_t VP_E1_MIN_EX_T = 0x2618;
+
+ constexpr uint16_t VP_Fan0_Percentage = 0x2700; // 2 Byte Integer (0..100)
+ constexpr uint16_t VP_Fan1_Percentage = 0x2702; // 2 Byte Integer (0..100)
+ constexpr uint16_t VP_Fan2_Percentage = 0x2704; // 2 Byte Integer (0..100)
+ constexpr uint16_t VP_Fan3_Percentage = 0x2706; // 2 Byte Integer (0..100)
+ constexpr uint16_t VP_Feedrate_Percentage = 0x2708; // 2 Byte Integer (0..100)
+
+ // Fan status
+ constexpr uint16_t VP_FAN0_STATUS = 0x2710;
+ constexpr uint16_t VP_FAN1_STATUS = 0x2712;
+ constexpr uint16_t VP_FAN2_STATUS = 0x2714;
+ constexpr uint16_t VP_FAN3_STATUS = 0x2716;
+
+ // Step per mm
+ constexpr uint16_t VP_X_STEP_PER_MM = 0x2900; // at the moment , 2 byte unsigned int , 0~1638.4
+ constexpr uint16_t VP_Y_STEP_PER_MM = 0x2904;
+ constexpr uint16_t VP_Z_STEP_PER_MM = 0x2908;
+ constexpr uint16_t VP_E0_STEP_PER_MM = 0x2910;
+ constexpr uint16_t VP_E1_STEP_PER_MM = 0x2912;
+ constexpr uint16_t VP_E2_STEP_PER_MM = 0x2914;
+ constexpr uint16_t VP_E3_STEP_PER_MM = 0x2916;
+ constexpr uint16_t VP_E4_STEP_PER_MM = 0x2918;
+ constexpr uint16_t VP_E5_STEP_PER_MM = 0x291A;
+ constexpr uint16_t VP_E6_STEP_PER_MM = 0x291C;
+ constexpr uint16_t VP_E7_STEP_PER_MM = 0x291E;
+
+ constexpr uint16_t VP_X_MAX_SPEED = 0x2A00;
+ constexpr uint16_t VP_Y_MAX_SPEED = 0x2A04;
+ constexpr uint16_t VP_Z_MAX_SPEED = 0x2A08;
+ constexpr uint16_t VP_E0_MAX_SPEED = 0x2A0C;
+ constexpr uint16_t VP_E1_MAX_SPEED = 0x2A10;
+
+ constexpr uint16_t VP_X_ACC_MAX_SPEED = 0x2A28;
+ constexpr uint16_t VP_Y_ACC_MAX_SPEED = 0x2A2C;
+ constexpr uint16_t VP_Z_ACC_MAX_SPEED = 0x2A30;
+ constexpr uint16_t VP_E0_ACC_MAX_SPEED = 0x2A34;
+ constexpr uint16_t VP_E1_ACC_MAX_SPEED = 0x2A38;
+
+ constexpr uint16_t VP_TRAVEL_SPEED = 0x2A3C;
+ constexpr uint16_t VP_FEEDRATE_MIN_SPEED = 0x2A40;
+ constexpr uint16_t VP_T_F_SPEED = 0x2A44;
+ constexpr uint16_t VP_ACC_SPEED = 0x2A48;
+
+ /* -------------------------------0x3000-0x3FFF------------------------------- */
+ // Buttons on the SD-Card File listing.
+ constexpr uint16_t VP_SD_ScrollEvent = 0x3020; // Data: 0 for "up a directory", numbers are the amount to scroll, e.g -1 one up, 1 one down
+ constexpr uint16_t VP_SD_FileSelected = 0x3022; // Number of file field selected.
+ constexpr uint16_t VP_SD_FileSelectConfirm = 0x3024; // (This is a virtual VP and emulated by the Confirm Screen when a file has been confirmed)
+ constexpr uint16_t VP_SD_ResumePauseAbort = 0x3026; // Resume(Data=0), Pause(Data=1), Abort(Data=2) SD Card prints
+ constexpr uint16_t VP_SD_AbortPrintConfirmed = 0x3028; // Abort print confirmation (virtual, will be injected by the confirm dialog)
+ constexpr uint16_t VP_SD_Print_Setting = 0x3040;
+ constexpr uint16_t VP_SD_Print_LiveAdjustZ = 0x3050; // Data: 0 down, 1 up
+ constexpr uint16_t VP_SD_Print_LiveAdjustZ_Confirm = 0x3060;
+ constexpr uint16_t VP_ZOffset_Distance = 0x3070;
+ constexpr uint16_t VP_ZOffset_DE_DIS = 0x3080;
+ constexpr uint16_t VP_SD_FileSelect_Back = 0x3082;
+ // SDCard File Listing
+ constexpr uint16_t VP_SD_FileName_LEN = 32; // LEN is shared for all entries.
+ constexpr uint16_t DGUS_SD_FILESPERSCREEN = 10; // FIXME move that info to the display and read it from there.
+ constexpr uint16_t VP_SD_FileName0 = 0x3100;
+ constexpr uint16_t VP_SD_FileName1 = 0x3120;
+ constexpr uint16_t VP_SD_FileName2 = 0x3140;
+ constexpr uint16_t VP_SD_FileName3 = 0x3160;
+ constexpr uint16_t VP_SD_FileName4 = 0x3180;
+ constexpr uint16_t VP_SD_FileName5 = 0x31A0;
+ constexpr uint16_t VP_SD_FileName6 = 0x31C0;
+ constexpr uint16_t VP_SD_FileName7 = 0x31E0;
+ constexpr uint16_t VP_SD_FileName8 = 0x3200;
+ constexpr uint16_t VP_SD_FileName9 = 0x3220;
+
+ constexpr uint16_t VP_SD_Print_ProbeOffsetZ = 0x32A0;
+ constexpr uint16_t VP_SD_Print_Baby = 0x32B0;
+ constexpr uint16_t VP_SD_Print_Filename = 0x32C0;
+
+ // X Y Z Point
+ constexpr uint16_t VP_XPos = 0x3300; // 4 Byte Fixed point number; format xxx.yy
+ constexpr uint16_t VP_YPos = 0x3302; // 4 Byte Fixed point number; format xxx.yy
+ constexpr uint16_t VP_ZPos = 0x3304; // 4 Byte Fixed point number; format xxx.yy
+ constexpr uint16_t VP_EPos = 0x3306; // 4 Byte Fixed point number; format xxx.yy
+
+ // Print
+ constexpr uint16_t VP_PrintProgress_Percentage = 0x3330; // 2 Byte Integer (0..100)
+ constexpr uint16_t VP_PrintTime = 0x3340;
+ constexpr uint16_t VP_PrintTime_LEN = 32;
+ constexpr uint16_t VP_PrintAccTime = 0x3360;
+ constexpr uint16_t VP_PrintAccTime_LEN = 32;
+ constexpr uint16_t VP_PrintsTotal = 0x3380;
+ constexpr uint16_t VP_PrintsTotal_LEN = 16;
+
+ constexpr uint16_t VP_File_Pictutr0 = 0x3400;
+ constexpr uint16_t VP_File_Pictutr1 = 0x3402;
+ constexpr uint16_t VP_File_Pictutr2 = 0x3404;
+ constexpr uint16_t VP_File_Pictutr3 = 0x3406;
+ constexpr uint16_t VP_File_Pictutr4 = 0x3408;
+ constexpr uint16_t VP_File_Pictutr5 = 0x340A;
+ constexpr uint16_t VP_File_Pictutr6 = 0x340C;
+ constexpr uint16_t VP_File_Pictutr7 = 0x340E;
+ constexpr uint16_t VP_File_Pictutr8 = 0x3410;
+ constexpr uint16_t VP_File_Pictutr9 = 0x3412;
+
+ constexpr uint16_t VP_BED_STATUS = 0x341C;
+
+ constexpr uint16_t VP_TMC_X_STEP = 0x3430;
+ constexpr uint16_t VP_TMC_Y_STEP = 0x3432;
+ constexpr uint16_t VP_TMC_Z_STEP = 0x3434;
+
+ constexpr uint16_t VP_TMC_X1_Current = 0x3436;
+ constexpr uint16_t VP_TMC_Y1_Current = 0x3438;
+ constexpr uint16_t VP_TMC_X_Current = 0x343A;
+ constexpr uint16_t VP_TMC_Y_Current = 0x343C;
+ constexpr uint16_t VP_TMC_Z_Current = 0x343E;
+ constexpr uint16_t VP_TMC_E0_Current = 0x3440;
+ constexpr uint16_t VP_TMC_E1_Current = 0x3442;
+ constexpr uint16_t VP_TMC_Z1_Current = 0x3444;
+
+
+ constexpr uint16_t VP_PrintTime_H = 0x3500;
+ constexpr uint16_t VP_PrintTime_M = 0x3502;
+ constexpr uint16_t VP_PrintTime_S = 0x3504;
+
+ // PIDs
+ constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , 2 byte unsigned int , 0~1638.4
+ constexpr uint16_t VP_E0_PID_I = 0x3702;
+ constexpr uint16_t VP_E0_PID_D = 0x3704;
+ constexpr uint16_t VP_E1_PID_P = 0x3706; // at the moment , 2 byte unsigned int , 0~1638.4
+ constexpr uint16_t VP_E1_PID_I = 0x3708;
+ constexpr uint16_t VP_E1_PID_D = 0x370A;
+ constexpr uint16_t VP_BED_PID_P = 0x3710;
+ constexpr uint16_t VP_BED_PID_I = 0x3712;
+ constexpr uint16_t VP_BED_PID_D = 0x3714;
+
+ constexpr uint16_t VP_EEPROM_CTRL = 0x3720;
+
+ constexpr uint16_t VP_OFFSET_X = 0x3724;
+ constexpr uint16_t VP_OFFSET_Y = 0x3728;
+ constexpr uint16_t VP_OFFSET_Z = 0x372B;
+
+ // PID autotune
+ constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x3800;
+ constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x3802;
+ constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x3804;
+ constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x3806;
+ constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x3808;
+ constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x380A;
+ constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x380C;
+ // Calibrate Z
+ constexpr uint16_t VP_Z_CALIBRATE = 0x3810;
+
+ constexpr uint16_t VP_AutoTurnOffSw = 0x3812;
+ constexpr uint16_t VP_LCD_BLK = 0x3814;
+
+ constexpr uint16_t VP_X_PARK_POS = 0x3900;
+ constexpr uint16_t VP_Y_PARK_POS = 0x3902;
+ constexpr uint16_t VP_Z_PARK_POS = 0x3904;
+
+ /* -------------------------------0x4000-0x4FFF------------------------------- */
+ // Heater Control Buttons , triged between "cool down" and "heat PLA" state
+ constexpr uint16_t VP_E0_CONTROL = 0x4010;
+ constexpr uint16_t VP_E1_CONTROL = 0x4012;
+ //constexpr uint16_t VP_E2_CONTROL = 0x2214;
+ //constexpr uint16_t VP_E3_CONTROL = 0x2216;
+ //constexpr uint16_t VP_E4_CONTROL = 0x2218;
+ //constexpr uint16_t VP_E5_CONTROL = 0x221A;
+ constexpr uint16_t VP_BED_CONTROL = 0x401C;
+
+ // Preheat
+ constexpr uint16_t VP_E0_BED_PREHEAT = 0x4020;
+ constexpr uint16_t VP_E1_BED_PREHEAT = 0x4022;
+ //constexpr uint16_t VP_E2_BED_PREHEAT = 0x4024;
+ //constexpr uint16_t VP_E3_BED_PREHEAT = 0x4026;
+ //constexpr uint16_t VP_E4_BED_PREHEAT = 0x4028;
+ //constexpr uint16_t VP_E5_BED_PREHEAT = 0x402A;
+
+ // Filament load and unload
+ // constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x4030;
+ // constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x4032;
+
+ // Settings store , reset
+
+ // Level data
+ constexpr uint16_t VP_Level_Point_One_X = 0x4100;
+ constexpr uint16_t VP_Level_Point_One_Y = 0x4102;
+ constexpr uint16_t VP_Level_Point_Two_X = 0x4104;
+ constexpr uint16_t VP_Level_Point_Two_Y = 0x4106;
+ constexpr uint16_t VP_Level_Point_Three_X = 0x4108;
+ constexpr uint16_t VP_Level_Point_Three_Y = 0x410A;
+ constexpr uint16_t VP_Level_Point_Four_X = 0x410C;
+ constexpr uint16_t VP_Level_Point_Four_Y = 0x410E;
+ constexpr uint16_t VP_Level_Point_Five_X = 0x4110;
+ constexpr uint16_t VP_Level_Point_Five_Y = 0x4112;
+
+
+ /* H43 Version */
+ constexpr uint16_t VP_MKS_H43_VERSION = 0x4A00; // MKS H43 V1.0.0
+ constexpr uint16_t VP_MKS_H43_VERSION_LEN = 16;
+ constexpr uint16_t VP_MKS_H43_UpdataVERSION = 0x4A10; // MKS H43 V1.0.0
+ constexpr uint16_t VP_MKS_H43_UpdataVERSION_LEN = 16;
+
+ /* -------------------------------0x5000-0xFFFF------------------------------- */
+ constexpr uint16_t VP_HOME_Dis = 0x5000;
+ constexpr uint16_t VP_Setting_Dis = 0x5010;
+ constexpr uint16_t VP_Tool_Dis = 0x5020;
+ constexpr uint16_t VP_Printing_Dis = 0x5030;
+
+ constexpr uint16_t VP_Language_Dis = 0x5080;
+ constexpr uint16_t VP_LossPoint_Dis = 0x5090;
+
+ constexpr uint16_t VP_PrintPauseConfig_Dis = 0x5120;
+ constexpr uint16_t VP_MotorPluse_Dis = 0x5140;
+ constexpr uint16_t VP_MotorMaxSpeed_Dis = 0x5150;
+ constexpr uint16_t VP_MotorMaxAcc_Dis = 0x5160;
+
+ constexpr uint16_t VP_X_Pluse_Dis = 0x5170;
+ constexpr uint16_t VP_Y_Pluse_Dis = 0x5180;
+ constexpr uint16_t VP_Z_Pluse_Dis = 0x5190;
+ constexpr uint16_t VP_E0_Pluse_Dis = 0x51A0;
+ constexpr uint16_t VP_E1_Pluse_Dis = 0x51B0;
+
+ constexpr uint16_t VP_X_Max_Speed_Dis = 0x5280;
+ constexpr uint16_t VP_Y_Max_Speed_Dis = 0x5290;
+ constexpr uint16_t VP_Z_Max_Speed_Dis = 0x52A0;
+ constexpr uint16_t VP_E0_Max_Speed_Dis = 0x52B0;
+ constexpr uint16_t VP_E1_Max_Speed_Dis = 0x52C0;
+
+ constexpr uint16_t VP_X_Max_Acc_Speed_Dis = 0x51E0;
+ constexpr uint16_t VP_Y_Max_Acc_Speed_Dis = 0x51F0;
+ constexpr uint16_t VP_Z_Max_Acc_Speed_Dis = 0x5200;
+ constexpr uint16_t VP_E0_Max_Acc_Speed_Dis = 0x5210;
+ constexpr uint16_t VP_E1_Max_Acc_Speed_Dis = 0x5220;
+
+
+ constexpr uint16_t VP_PrintTime_Dis = 0x5470;
+ constexpr uint16_t VP_E0_Temp_Dis = 0x5310;
+ constexpr uint16_t VP_E1_Temp_Dis = 0x5320;
+ constexpr uint16_t VP_HB_Temp_Dis = 0x5330;
+ constexpr uint16_t VP_Feedrate_Dis = 0x5350;
+ constexpr uint16_t VP_PrintAcc_Dis = 0x5340;
+ constexpr uint16_t VP_Fan_Speed_Dis = 0x5360;
+
+ constexpr uint16_t VP_Min_Ex_Temp_Dis = 0x5380;
+
+
+ constexpr uint16_t VP_X_PARK_POS_Dis = 0x53E0;
+ constexpr uint16_t VP_Y_PARK_POS_Dis = 0x53F0;
+ constexpr uint16_t VP_Z_PARK_POS_Dis = 0x5400;
+
+
+ constexpr uint16_t VP_TravelAcc_Dis = 0x5440;
+ constexpr uint16_t VP_FeedRateMin_Dis = 0x5450;
+ constexpr uint16_t VP_TravelFeeRateMin_Dis = 0x5460;
+ constexpr uint16_t VP_ACC_Dis = 0x5480;
+
+ constexpr uint16_t VP_Extrusion_Dis = 0x5230;
+ constexpr uint16_t VP_HeatBed_Dis = 0x5240;
+
+ constexpr uint16_t VP_Printting_Dis = 0x5430;
+ constexpr uint16_t VP_FactoryDefaults_Dis = 0x54C0;
+ constexpr uint16_t VP_StoreSetting_Dis = 0x54B0;
+ constexpr uint16_t VP_Info_EEPROM_2_Dis = 0x54D0;
+ constexpr uint16_t VP_Info_EEPROM_1_Dis = 0x54E0;
+
+ constexpr uint16_t VP_AutoLevel_1_Dis = 0x55F0;
+
+ constexpr uint16_t VP_TMC_X_Step_Dis = 0x5530;
+ constexpr uint16_t VP_TMC_Y_Step_Dis = 0x5540;
+ constexpr uint16_t VP_TMC_Z_Step_Dis = 0x5550;
+ constexpr uint16_t VP_TMC_X1_Current_Dis = 0x5560;
+ constexpr uint16_t VP_TMC_Y1_Current_Dis = 0x5570;
+ constexpr uint16_t VP_TMC_X_Current_Dis = 0x5580;
+ constexpr uint16_t VP_TMC_Y_Current_Dis = 0x5590;
+ constexpr uint16_t VP_TMC_Z_Current_Dis = 0x55A0;
+ constexpr uint16_t VP_TMC_E0_Current_Dis = 0x55B0;
+ constexpr uint16_t VP_TMC_E1_Current_Dis = 0x55C0;
+ constexpr uint16_t VP_TMC_Z1_Current_Dis = 0x55E0;
+
+ constexpr uint16_t VP_AutoLEVEL_INFO1 = 0x5600;
+ constexpr uint16_t VP_EX_TEMP_INFO1_Dis = 0x5610;
+ constexpr uint16_t VP_EX_TEMP_INFO2_Dis = 0x5620;
+ constexpr uint16_t VP_EX_TEMP_INFO3_Dis = 0x5630;
+ constexpr uint16_t VP_LCD_BLK_Dis = 0x56A0;
+ constexpr uint16_t VP_Info_PrintFinish_1_Dis = 0x5C00;
+ constexpr uint16_t VP_Info_PrintFinish_2_Dis = 0x5C10;
+
+ constexpr uint16_t VP_Length_Dis = 0x5B00;
+
+ constexpr uint16_t VP_PrintConfrim_Info_Dis = 0x5B90;
+ constexpr uint16_t VP_StopPrintConfrim_Info_Dis = 0x5B80;
+
+ constexpr uint16_t VP_Point_One_Dis = 0x5BA0;
+ constexpr uint16_t VP_Point_Two_Dis = 0x5BB0;
+ constexpr uint16_t VP_Point_Three_Dis = 0x5BC0;
+ constexpr uint16_t VP_Point_Four_Dis = 0x5BD0;
+ constexpr uint16_t VP_Point_Five_Dis = 0x5BE0;
+
+ constexpr uint16_t VP_Print_Dis = 0x5250;
+
+ constexpr uint16_t VP_About_Dis = 0x5A00;
+ constexpr uint16_t VP_Config_Dis = 0x5A10;
+ constexpr uint16_t VP_Filament_Dis = 0x5A20;
+ constexpr uint16_t VP_Move_Dis = 0x5A30;
+ constexpr uint16_t VP_Level_Dis = 0x5A50;
+ constexpr uint16_t VP_Speed_Dis = 0x5A70;
+ constexpr uint16_t VP_InOut_Dis = 0x5A80;
+
+ constexpr uint16_t VP_MotorConfig_Dis = 0x5100;
+ constexpr uint16_t VP_LevelConfig_Dis = 0x5110;
+ constexpr uint16_t VP_Advance_Dis = 0x5130;
+ constexpr uint16_t VP_TemperatureConfig_Dis = 0x5390;
+
+#endif // MKS_FINSH
diff --git a/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp b/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp
new file mode 100644
index 0000000..531788c
--- /dev/null
+++ b/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp
@@ -0,0 +1,2028 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_MKS)
+
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../inc/MarlinConfig.h"
+
+#include "../../../../MarlinCore.h"
+#include "../../../../module/settings.h"
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+#include "../../../../module/printcounter.h"
+
+#include "../../../../gcode/gcode.h"
+
+#if HAS_STEALTHCHOP
+ #include "../../../../module/stepper/trinamic.h"
+ #include "../../../../module/stepper/indirection.h"
+#endif
+#include "../../../../module/probe.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if ENABLED(SDSUPPORT)
+ extern ExtUI::FileList filelist;
+#endif
+
+bool DGUSAutoTurnOff = false;
+MKS_Language mks_language_index; // Initialized by settings.load()
+
+// endianness swap
+uint32_t swap32(const uint32_t value) { return (value & 0x000000FFU) << 24U | (value & 0x0000FF00U) << 8U | (value & 0x00FF0000U) >> 8U | (value & 0xFF000000U) >> 24U; }
+
+#if 0
+void DGUSScreenHandlerMKS::sendinfoscreen_ch(const uint16_t *line1, const uint16_t *line2, const uint16_t *line3, const uint16_t *line4) {
+ dgusdisplay.WriteVariable(VP_MSGSTR1, line1, 32, true);
+ dgusdisplay.WriteVariable(VP_MSGSTR2, line2, 32, true);
+ dgusdisplay.WriteVariable(VP_MSGSTR3, line3, 32, true);
+ dgusdisplay.WriteVariable(VP_MSGSTR4, line4, 32, true);
+}
+
+void DGUSScreenHandlerMKS::sendinfoscreen_en(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4) {
+ dgusdisplay.WriteVariable(VP_MSGSTR1, line1, 32, true);
+ dgusdisplay.WriteVariable(VP_MSGSTR2, line2, 32, true);
+ dgusdisplay.WriteVariable(VP_MSGSTR3, line3, 32, true);
+ dgusdisplay.WriteVariable(VP_MSGSTR4, line4, 32, true);
+}
+
+void DGUSScreenHandlerMKS::sendinfoscreen(const void *line1, const void *line2, const void *line3, const void *line4, uint16_t language) {
+ if (language == MKS_English)
+ DGUSScreenHandlerMKS::sendinfoscreen_en((char *)line1, (char *)line2, (char *)line3, (char *)line4);
+ else if (language == MKS_SimpleChinese)
+ DGUSScreenHandlerMKS::sendinfoscreen_ch((uint16_t *)line1, (uint16_t *)line2, (uint16_t *)line3, (uint16_t *)line4);
+}
+
+#endif
+
+void DGUSScreenHandlerMKS::DGUSLCD_SendFanToDisplay(DGUS_VP_Variable &var) {
+ if (var.memadr) {
+ //DEBUG_ECHOPGM(" DGUS_LCD_SendWordValueToDisplay ", var.VP);
+ //DEBUG_ECHOLNPGM(" data ", *(uint16_t *)var.memadr);
+ uint16_t tmp = *(uint8_t *) var.memadr; // +1 -> avoid rounding issues for the display.
+ // tmp = map(tmp, 0, 255, 0, 100);
+ dgusdisplay.WriteVariable(var.VP, tmp);
+ }
+}
+
+void DGUSScreenHandlerMKS::DGUSLCD_SendBabyStepToDisplay(DGUS_VP_Variable &var) {
+ float value = current_position.z;
+ DEBUG_ECHOLNPAIR_F(" >> ", value, 6);
+ value *= cpow(10, 2);
+ dgusdisplay.WriteVariable(VP_SD_Print_Baby, (uint16_t)value);
+}
+
+void DGUSScreenHandlerMKS::DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var) {
+ duration_t elapsed = print_job_timer.duration();
+ uint32_t time = elapsed.value;
+ dgusdisplay.WriteVariable(VP_PrintTime_H, uint16_t(time / 3600));
+ dgusdisplay.WriteVariable(VP_PrintTime_M, uint16_t(time % 3600 / 60));
+ dgusdisplay.WriteVariable(VP_PrintTime_S, uint16_t((time % 3600) % 60));
+}
+
+void DGUSScreenHandlerMKS::DGUSLCD_SetUint8(DGUS_VP_Variable &var, void *val_ptr) {
+ if (var.memadr) {
+ const uint16_t value = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("FAN value get:", value);
+ *(uint8_t*)var.memadr = map(constrain(value, 0, 255), 0, 255, 0, 255);
+ DEBUG_ECHOLNPGM("FAN value change:", *(uint8_t*)var.memadr);
+ }
+}
+
+void DGUSScreenHandlerMKS::DGUSLCD_SendGbkToDisplay(DGUS_VP_Variable &var) {
+ DEBUG_ECHOLNPGM(" data ", *(uint16_t *)var.memadr);
+ uint16_t *tmp = (uint16_t*) var.memadr;
+ dgusdisplay.WriteVariable(var.VP, tmp, var.size, true);
+}
+
+void DGUSScreenHandlerMKS::DGUSLCD_SendStringToDisplay_Language(DGUS_VP_Variable &var) {
+ if (mks_language_index == MKS_English) {
+ char *tmp = (char*) var.memadr;
+ dgusdisplay.WriteVariable(var.VP, tmp, var.size, true);
+ }
+ else if (mks_language_index == MKS_SimpleChinese) {
+ uint16_t *tmp = (uint16_t *)var.memadr;
+ dgusdisplay.WriteVariable(var.VP, tmp, var.size, true);
+ }
+}
+
+void DGUSScreenHandlerMKS::DGUSLCD_SendTMCStepValue(DGUS_VP_Variable &var) {
+ #if ENABLED(SENSORLESS_HOMING)
+ #if X_HAS_STEALTHCHOP
+ tmc_step.x = stepperX.homing_threshold();
+ dgusdisplay.WriteVariable(var.VP, *(int16_t*)var.memadr);
+ #endif
+ #if Y_HAS_STEALTHCHOP
+ tmc_step.y = stepperY.homing_threshold();
+ dgusdisplay.WriteVariable(var.VP, *(int16_t*)var.memadr);
+ #endif
+ #if Z_HAS_STEALTHCHOP
+ tmc_step.z = stepperZ.homing_threshold();
+ dgusdisplay.WriteVariable(var.VP, *(int16_t*)var.memadr);
+ #endif
+ #endif
+}
+
+#if ENABLED(SDSUPPORT)
+
+ void DGUSScreenHandler::DGUSLCD_SD_FileSelected(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t touched_nr = (int16_t)swap16(*(uint16_t*)val_ptr) + top_file;
+ if (touched_nr != 0x0F && touched_nr > filelist.count()) return;
+ if (!filelist.seek(touched_nr) && touched_nr != 0x0F) return;
+
+ if (touched_nr == 0x0F) {
+ if (filelist.isAtRootDir())
+ GotoScreen(DGUSLCD_SCREEN_MAIN);
+ else
+ filelist.upDir();
+ return;
+ }
+
+ if (filelist.isDir()) {
+ filelist.changeDir(filelist.filename());
+ top_file = 0;
+ ForceCompleteUpdate();
+ return;
+ }
+
+ #if ENABLED(DGUS_PRINT_FILENAME)
+ // Send print filename
+ dgusdisplay.WriteVariable(VP_SD_Print_Filename, filelist.filename(), VP_SD_FileName_LEN, true);
+ #endif
+
+ // Setup Confirmation screen
+ file_to_print = touched_nr;
+ GotoScreen(MKSLCD_SCREEN_PRINT_CONFIRM);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_StartPrint(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!filelist.seek(file_to_print)) return;
+ ExtUI::printFile(filelist.shortFilename());
+ GotoScreen(MKSLCD_SCREEN_PRINT);
+ z_offset_add = 0;
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_ResumePauseAbort(DGUS_VP_Variable &var, void *val_ptr) {
+
+ if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
+ switch (swap16(*(uint16_t*)val_ptr)) {
+ case 0: { // Resume
+ auto cs = getCurrentScreen();
+ if (runout_mks.runout_status != RUNOUT_WAITING_STATUS && runout_mks.runout_status != UNRUNOUT_STATUS) {
+ if (cs == MKSLCD_SCREEN_PRINT || cs == MKSLCD_SCREEN_PAUSE)
+ GotoScreen(MKSLCD_SCREEN_PAUSE);
+ return;
+ }
+ else
+ runout_mks.runout_status = UNRUNOUT_STATUS;
+
+ GotoScreen(MKSLCD_SCREEN_PRINT);
+
+ if (ExtUI::isPrintingFromMediaPaused()) {
+ nozzle_park_mks.print_pause_start_flag = 0;
+ nozzle_park_mks.blstatus = true;
+ ExtUI::resumePrint();
+ }
+ } break;
+
+ case 1: // Pause
+ GotoScreen(MKSLCD_SCREEN_PAUSE);
+ if (!ExtUI::isPrintingFromMediaPaused()) {
+ nozzle_park_mks.print_pause_start_flag = 1;
+ nozzle_park_mks.blstatus = true;
+ ExtUI::pausePrint();
+ //ExtUI::mks_pausePrint();
+ }
+ break;
+
+ case 2: // Abort
+ HandleUserConfirmationPopUp(VP_SD_AbortPrintConfirmed, nullptr, PSTR("Abort printing"), filelist.filename(), PSTR("?"), true, true, false, true);
+ break;
+ }
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_SendFilename(DGUS_VP_Variable& var) {
+ uint16_t target_line = (var.VP - VP_SD_FileName0) / VP_SD_FileName_LEN;
+ if (target_line > DGUS_SD_FILESPERSCREEN) return;
+ char tmpfilename[VP_SD_FileName_LEN + 1] = "";
+ var.memadr = (void*)tmpfilename;
+
+ uint16_t dir_icon_val = 25;
+ if (filelist.seek(top_file + target_line)) {
+ snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s%c"), filelist.filename(), filelist.isDir() ? '/' : 0); // snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s"), filelist.filename());
+ dir_icon_val = filelist.isDir() ? 0 : 1;
+ }
+ DGUSLCD_SendStringToDisplay(var);
+
+ dgusdisplay.WriteVariable(VP_File_Pictutr0 + target_line * 2, dir_icon_val);
+ }
+
+ void DGUSScreenHandler::SDCardInserted() {
+ top_file = 0;
+ filelist.refresh();
+ auto cs = getCurrentScreen();
+ if (cs == DGUSLCD_SCREEN_MAIN || cs == DGUSLCD_SCREEN_STATUS)
+ GotoScreen(MKSLCD_SCREEN_CHOOSE_FILE);
+ }
+
+ void DGUSScreenHandler::SDCardRemoved() {
+ if (current_screen == DGUSLCD_SCREEN_SDFILELIST
+ || (current_screen == DGUSLCD_SCREEN_CONFIRM && (ConfirmVP == VP_SD_AbortPrintConfirmed || ConfirmVP == VP_SD_FileSelectConfirm))
+ || current_screen == DGUSLCD_SCREEN_SDPRINTMANIPULATION
+ ) filelist.refresh();
+ }
+
+ void DGUSScreenHandlerMKS::SDPrintingFinished() {
+ if (DGUSAutoTurnOff) {
+ queue.exhaust();
+ gcode.process_subcommands_now(F("M81"));
+ }
+ GotoScreen(MKSLCD_SCREEN_PrintDone);
+ }
+
+#else
+ void DGUSScreenHandlerMKS::PrintReturn(DGUS_VP_Variable& var, void *val_ptr) {
+ uint16_t value = swap16(*(uint16_t*)val_ptr);
+ if (value == 0x0F) GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+#endif // SDSUPPORT
+
+void DGUSScreenHandler::ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr) {
+ uint8_t *tmp = (uint8_t*)val_ptr;
+
+ // The keycode in target is coded as , so 0x0100A means
+ // from screen 1 (main) to 10 (temperature). DGUSLCD_SCREEN_POPUP is special,
+ // meaning "return to previous screen"
+ DGUSLCD_Screens target = (DGUSLCD_Screens)tmp[1];
+
+ DEBUG_ECHOLNPGM("\n DEBUG target", target);
+
+ // when the dgus had reboot, it will enter the DGUSLCD_SCREEN_MAIN page,
+ // so user can change any page to use this function, an it will check
+ // if robin nano is printing. when it is, dgus will enter the printing
+ // page to continue print;
+ //
+ //if (printJobOngoing() || printingIsPaused()) {
+ // if (target == MKSLCD_PAUSE_SETTING_MOVE || target == MKSLCD_PAUSE_SETTING_EX
+ // || target == MKSLCD_SCREEN_PRINT || target == MKSLCD_SCREEN_PAUSE
+ // ) {
+ // }
+ // else
+ // GotoScreen(MKSLCD_SCREEN_PRINT);
+ // return;
+ //}
+
+ if (target == DGUSLCD_SCREEN_POPUP) {
+ SetupConfirmAction(ExtUI::setUserConfirmed);
+
+ // Special handling for popup is to return to previous menu
+ if (current_screen == DGUSLCD_SCREEN_POPUP && confirm_action_cb) confirm_action_cb();
+ PopToOldScreen();
+ return;
+ }
+
+ UpdateNewScreen(target);
+
+ #ifdef DEBUG_DGUSLCD
+ if (!DGUSLCD_FindScreenVPMapList(target)) DEBUG_ECHOLNPGM("WARNING: No screen Mapping found for ", target);
+ #endif
+}
+
+void DGUSScreenHandlerMKS::ScreenBackChange(DGUS_VP_Variable &var, void *val_ptr) {
+ const uint16_t target = swap16(*(uint16_t *)val_ptr);
+ DEBUG_ECHOLNPGM(" back = 0x%x", target);
+ switch (target) {
+ }
+}
+
+void DGUSScreenHandlerMKS::ZoffsetConfirm(DGUS_VP_Variable &var, void *val_ptr) {
+ settings.save();
+ if (printJobOngoing())
+ GotoScreen(MKSLCD_SCREEN_PRINT);
+ else if (print_job_timer.isPaused)
+ GotoScreen(MKSLCD_SCREEN_PAUSE);
+}
+
+void DGUSScreenHandlerMKS::GetTurnOffCtrl(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("GetTurnOffCtrl\n");
+ const uint16_t value = swap16(*(uint16_t *)val_ptr);
+ switch (value) {
+ case 0 ... 1: DGUSAutoTurnOff = (bool)value; break;
+ default: break;
+ }
+}
+
+void DGUSScreenHandlerMKS::GetMinExtrudeTemp(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("GetMinExtrudeTemp");
+ const uint16_t value = swap16(*(uint16_t *)val_ptr);
+ TERN_(PREVENT_COLD_EXTRUSION, thermalManager.extrude_min_temp = value);
+ mks_min_extrusion_temp = value;
+ settings.save();
+}
+
+void DGUSScreenHandlerMKS::GetZoffsetDistance(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("GetZoffsetDistance");
+ const uint16_t value = swap16(*(uint16_t *)val_ptr);
+ float val_distance = 0;
+ switch (value) {
+ case 0: val_distance = 0.01; break;
+ case 1: val_distance = 0.1; break;
+ case 2: val_distance = 0.5; break;
+ case 3: val_distance = 1; break;
+ default: val_distance = 0.01; break;
+ }
+ ZOffset_distance = val_distance;
+}
+
+void DGUSScreenHandlerMKS::GetManualMovestep(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("\nGetManualMovestep");
+ *(uint16_t *)var.memadr = swap16(*(uint16_t *)val_ptr);
+}
+
+void DGUSScreenHandlerMKS::EEPROM_CTRL(DGUS_VP_Variable &var, void *val_ptr) {
+ const uint16_t eep_flag = swap16(*(uint16_t *)val_ptr);
+ switch (eep_flag) {
+ case 0:
+ settings.save();
+ settings.load(); // load eeprom data to check the data is right
+ GotoScreen(MKSLCD_SCREEN_EEP_Config);
+ break;
+
+ case 1:
+ settings.reset();
+ GotoScreen(MKSLCD_SCREEN_EEP_Config);
+ break;
+
+ default: break;
+ }
+}
+
+void DGUSScreenHandlerMKS::Z_offset_select(DGUS_VP_Variable &var, void *val_ptr) {
+ const uint16_t z_value = swap16(*(uint16_t *)val_ptr);
+ switch (z_value) {
+ case 0: Z_distance = 0.01; break;
+ case 1: Z_distance = 0.1; break;
+ case 2: Z_distance = 0.5; break;
+ default: Z_distance = 1; break;
+ }
+}
+
+void DGUSScreenHandlerMKS::GetOffsetValue(DGUS_VP_Variable &var, void *val_ptr) {
+
+ #if HAS_BED_PROBE
+ int32_t value = swap32(*(int32_t *)val_ptr);
+ float Offset = value / 100.0f;
+ DEBUG_ECHOLNPGM("\nget int6 offset >> ", value, 6);
+ #endif
+
+ switch (var.VP) {
+ case VP_OFFSET_X: TERN_(HAS_BED_PROBE, probe.offset.x = Offset); break;
+ case VP_OFFSET_Y: TERN_(HAS_BED_PROBE, probe.offset.y = Offset); break;
+ case VP_OFFSET_Z: TERN_(HAS_BED_PROBE, probe.offset.z = Offset); break;
+ default: break;
+ }
+ settings.save();
+}
+
+void DGUSScreenHandlerMKS::LanguageChange(DGUS_VP_Variable &var, void *val_ptr) {
+ const uint16_t lag_flag = swap16(*(uint16_t *)val_ptr);
+ switch (lag_flag) {
+ case MKS_SimpleChinese:
+ DGUS_LanguageDisplay(MKS_SimpleChinese);
+ mks_language_index = MKS_SimpleChinese;
+ dgusdisplay.WriteVariable(VP_LANGUAGE_CHANGE1, (uint8_t)MKS_Language_Choose);
+ dgusdisplay.WriteVariable(VP_LANGUAGE_CHANGE2, (uint8_t)MKS_Language_NoChoose);
+ settings.save();
+ break;
+ case MKS_English:
+ DGUS_LanguageDisplay(MKS_English);
+ mks_language_index = MKS_English;
+ dgusdisplay.WriteVariable(VP_LANGUAGE_CHANGE1, (uint8_t)MKS_Language_NoChoose);
+ dgusdisplay.WriteVariable(VP_LANGUAGE_CHANGE2, (uint8_t)MKS_Language_Choose);
+ settings.save();
+ break;
+ default: break;
+ }
+}
+
+#if ENABLED(MESH_BED_LEVELING)
+ uint8_t mesh_point_count = GRID_MAX_POINTS;
+#endif
+
+void DGUSScreenHandlerMKS::Level_Ctrl(DGUS_VP_Variable &var, void *val_ptr) {
+ const uint16_t lev_but = swap16(*(uint16_t *)val_ptr);
+ #if ENABLED(MESH_BED_LEVELING)
+ auto cs = getCurrentScreen();
+ #endif
+ switch (lev_but) {
+ case 0:
+ #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
+
+ static uint8_t a_first_level = 1;
+ if (a_first_level == 1) {
+ a_first_level = 0;
+ queue.enqueue_now_P(G28_STR);
+ }
+ queue.enqueue_now(F("G29"));
+
+ #elif ENABLED(MESH_BED_LEVELING)
+
+ mesh_point_count = GRID_MAX_POINTS;
+
+ if (mks_language_index == MKS_English) {
+ const char level_buf_en[] = "Start Level";
+ dgusdisplay.WriteVariable(VP_AutoLevel_1_Dis, level_buf_en, 32, true);
+ }
+ else if (mks_language_index == MKS_SimpleChinese) {
+ const uint16_t level_buf_ch[] = {0xAABF, 0xBCCA, 0xF7B5, 0xBDC6, 0x2000};
+ dgusdisplay.WriteVariable(VP_AutoLevel_1_Dis, level_buf_ch, 32, true);
+ }
+
+ cs = getCurrentScreen();
+ if (cs != MKSLCD_AUTO_LEVEL) GotoScreen(MKSLCD_AUTO_LEVEL);
+ #else
+
+ GotoScreen(MKSLCD_SCREEN_LEVEL);
+
+ #endif
+ break;
+
+ case 1:
+ soft_endstop._enabled = true;
+ GotoScreen(MKSLCD_SCREEM_TOOL);
+ break;
+
+ default: break;
+ }
+}
+
+void DGUSScreenHandlerMKS::MeshLevelDistanceConfig(DGUS_VP_Variable &var, void *val_ptr) {
+ const uint16_t mesh_dist = swap16(*(uint16_t *)val_ptr);
+ switch (mesh_dist) {
+ case 0: mesh_adj_distance = 0.01; break;
+ case 1: mesh_adj_distance = 0.1; break;
+ case 2: mesh_adj_distance = 1; break;
+ default: mesh_adj_distance = 0.1; break;
+ }
+}
+
+void DGUSScreenHandlerMKS::MeshLevel(DGUS_VP_Variable &var, void *val_ptr) {
+ #if ENABLED(MESH_BED_LEVELING)
+ const uint16_t mesh_value = swap16(*(uint16_t *)val_ptr);
+ // static uint8_t a_first_level = 1;
+ char cmd_buf[30];
+ float offset = mesh_adj_distance;
+ int16_t integer, Deci, Deci2;
+
+ if (!queue.ring_buffer.empty()) return;
+
+ switch (mesh_value) {
+ case 0:
+ offset = mesh_adj_distance;
+ integer = offset; // get int
+ Deci = (offset * 10);
+ Deci = Deci % 10;
+ Deci2 = offset * 100;
+ Deci2 = Deci2 % 10;
+ soft_endstop._enabled = false;
+ queue.enqueue_now(F("G91"));
+ snprintf_P(cmd_buf, 30, PSTR("G1 Z%d.%d%d"), integer, Deci, Deci2);
+ queue.enqueue_one_now(cmd_buf);
+ queue.enqueue_now(F("G90"));
+ //soft_endstop._enabled = true;
+ break;
+
+ case 1:
+ offset = mesh_adj_distance;
+ integer = offset; // get int
+ Deci = (offset * 10);
+ Deci = Deci % 10;
+ Deci2 = offset * 100;
+ Deci2 = Deci2 % 10;
+ soft_endstop._enabled = false;
+ queue.enqueue_now(F("G91"));
+ snprintf_P(cmd_buf, 30, PSTR("G1 Z-%d.%d%d"), integer, Deci, Deci2);
+ queue.enqueue_one_now(cmd_buf);
+ queue.enqueue_now(F("G90"));
+ break;
+
+ case 2:
+ if (mesh_point_count == GRID_MAX_POINTS) { // The first point
+
+ queue.enqueue_now(F("G28"));
+ queue.enqueue_now(F("G29S1"));
+ mesh_point_count--;
+
+ if (mks_language_index == MKS_English) {
+ const char level_buf_en1[] = "Next Point";
+ dgusdisplay.WriteVariable(VP_AutoLevel_1_Dis, level_buf_en1, 32, true);
+ }
+ else if (mks_language_index == MKS_SimpleChinese) {
+ const uint16_t level_buf_ch1[] = {0xC2CF, 0xBBD2, 0xE3B5, 0x2000};
+ dgusdisplay.WriteVariable(VP_AutoLevel_1_Dis, level_buf_ch1, 32, true);
+ }
+ }
+ else if (mesh_point_count > 1) { // 倒数第二个点
+ queue.enqueue_now(F("G29S2"));
+ mesh_point_count--;
+ if (mks_language_index == MKS_English) {
+ const char level_buf_en2[] = "Next Point";
+ dgusdisplay.WriteVariable(VP_AutoLevel_1_Dis, level_buf_en2, 32, true);
+ }
+ else if (mks_language_index == MKS_SimpleChinese) {
+ const uint16_t level_buf_ch2[] = {0xC2CF, 0xBBD2, 0xE3B5, 0x2000};
+ dgusdisplay.WriteVariable(VP_AutoLevel_1_Dis, level_buf_ch2, 32, true);
+ }
+ }
+ else if (mesh_point_count == 1) {
+ queue.enqueue_now(F("G29S2"));
+ mesh_point_count--;
+ if (mks_language_index == MKS_English) {
+ const char level_buf_en2[] = "Leveling Done";
+ dgusdisplay.WriteVariable(VP_AutoLevel_1_Dis, level_buf_en2, 32, true);
+ }
+ else if (mks_language_index == MKS_SimpleChinese) {
+ const uint16_t level_buf_ch2[] = {0xF7B5, 0xBDC6, 0xEACD, 0xC9B3, 0x2000};
+ dgusdisplay.WriteVariable(VP_AutoLevel_1_Dis, level_buf_ch2, 32, true);
+ }
+ settings.save();
+ }
+ else if (mesh_point_count == 0) {
+ mesh_point_count = GRID_MAX_POINTS;
+ soft_endstop._enabled = true;
+ settings.save();
+ GotoScreen(MKSLCD_SCREEM_TOOL);
+ }
+ break;
+
+ default:
+ break;
+ }
+ #endif // MESH_BED_LEVELING
+}
+
+void DGUSScreenHandlerMKS::SD_FileBack(DGUS_VP_Variable&, void*) {
+ GotoScreen(MKSLCD_SCREEN_HOME);
+}
+
+void DGUSScreenHandlerMKS::LCD_BLK_Adjust(DGUS_VP_Variable &var, void *val_ptr) {
+ const uint16_t lcd_value = swap16(*(uint16_t *)val_ptr);
+
+ lcd_default_light = constrain(lcd_value, 10, 100);
+
+ const uint16_t lcd_data[2] = { lcd_default_light, lcd_default_light };
+ dgusdisplay.WriteVariable(0x0082, &lcd_data, 5, true);
+}
+
+void DGUSScreenHandlerMKS::ManualAssistLeveling(DGUS_VP_Variable &var, void *val_ptr) {
+ const int16_t point_value = swap16(*(uint16_t *)val_ptr);
+
+ // Insist on leveling first time at this screen
+ static bool first_level_flag = false;
+ if (!first_level_flag || point_value == 0x0001) {
+ queue.enqueue_now_P(G28_STR);
+ first_level_flag = true;
+ }
+
+ constexpr uint16_t level_speed = 1500;
+
+ auto enqueue_corner_move = [](int16_t lx, int16_t ly, uint16_t fr) {
+ char buf_level[32];
+ sprintf_P(buf_level, "G0X%dY%dF%d", lx, ly, fr);
+ queue.enqueue_one_now(buf_level);
+ };
+
+ if (WITHIN(point_value, 0x0001, 0x0005))
+ queue.enqueue_now(F("G1Z10"));
+
+ switch (point_value) {
+ case 0x0001:
+ enqueue_corner_move(X_MIN_POS + ABS(mks_corner_offsets[0].x),
+ Y_MIN_POS + ABS(mks_corner_offsets[0].y), level_speed);
+ queue.enqueue_now(F("G28Z"));
+ break;
+ case 0x0002:
+ enqueue_corner_move(X_MAX_POS - ABS(mks_corner_offsets[1].x),
+ Y_MIN_POS + ABS(mks_corner_offsets[1].y), level_speed);
+ break;
+ case 0x0003:
+ enqueue_corner_move(X_MAX_POS - ABS(mks_corner_offsets[2].x),
+ Y_MAX_POS - ABS(mks_corner_offsets[2].y), level_speed);
+ break;
+ case 0x0004:
+ enqueue_corner_move(X_MIN_POS + ABS(mks_corner_offsets[3].x),
+ Y_MAX_POS - ABS(mks_corner_offsets[3].y), level_speed);
+ break;
+ case 0x0005:
+ enqueue_corner_move(ABS(mks_corner_offsets[4].x),
+ ABS(mks_corner_offsets[4].y), level_speed);
+ break;
+ }
+
+ if (WITHIN(point_value, 0x0002, 0x0005)) {
+ //queue.enqueue_now(F("G28Z"));
+ queue.enqueue_now(F("G1Z-10"));
+ }
+}
+
+#define mks_min(a, b) ((a) < (b)) ? (a) : (b)
+#define mks_max(a, b) ((a) > (b)) ? (a) : (b)
+void DGUSScreenHandlerMKS::TMC_ChangeConfig(DGUS_VP_Variable &var, void *val_ptr) {
+ #if EITHER(HAS_TRINAMIC_CONFIG, HAS_STEALTHCHOP)
+ const uint16_t tmc_value = swap16(*(uint16_t*)val_ptr);
+ #endif
+
+ switch (var.VP) {
+ case VP_TMC_X_STEP:
+ #if USE_SENSORLESS
+ #if X_HAS_STEALTHCHOP
+ stepperX.homing_threshold(mks_min(tmc_value, 255));
+ settings.save();
+ //tmc_step.x = stepperX.homing_threshold();
+ #endif
+ #endif
+ break;
+ case VP_TMC_Y_STEP:
+ #if USE_SENSORLESS
+ #if Y_HAS_STEALTHCHOP
+ stepperY.homing_threshold(mks_min(tmc_value, 255));
+ settings.save();
+ //tmc_step.y = stepperY.homing_threshold();
+ #endif
+ #endif
+ break;
+ case VP_TMC_Z_STEP:
+ #if USE_SENSORLESS
+ #if Z_HAS_STEALTHCHOP
+ stepperZ.homing_threshold(mks_min(tmc_value, 255));
+ settings.save();
+ //tmc_step.z = stepperZ.homing_threshold();
+ #endif
+ #endif
+ break;
+ case VP_TMC_X_Current:
+ #if AXIS_IS_TMC(X)
+ stepperX.rms_current(tmc_value);
+ settings.save();
+ #endif
+ break;
+ case VP_TMC_X1_Current:
+ #if AXIS_IS_TMC(X2)
+ stepperX2.rms_current(tmc_value);
+ settings.save();
+ #endif
+ break;
+ case VP_TMC_Y_Current:
+ #if AXIS_IS_TMC(Y)
+ stepperY.rms_current(tmc_value);
+ settings.save();
+ #endif
+ break;
+ case VP_TMC_Y1_Current:
+ #if AXIS_IS_TMC(X2)
+ stepperY2.rms_current(tmc_value);
+ settings.save();
+ #endif
+ break;
+ case VP_TMC_Z_Current:
+ #if AXIS_IS_TMC(Z)
+ stepperZ.rms_current(tmc_value);
+ settings.save();
+ #endif
+ break;
+ case VP_TMC_Z1_Current:
+ #if AXIS_IS_TMC(Z2)
+ stepperZ2.rms_current(tmc_value);
+ settings.save();
+ #endif
+ break;
+ case VP_TMC_E0_Current:
+ #if AXIS_IS_TMC(E0)
+ stepperE0.rms_current(tmc_value);
+ settings.save();
+ #endif
+ break;
+ case VP_TMC_E1_Current:
+ #if AXIS_IS_TMC(E1)
+ stepperE1.rms_current(tmc_value);
+ settings.save();
+ #endif
+ break;
+
+ default:
+ break;
+ }
+ #if USE_SENSORLESS
+ TERN_(X_HAS_STEALTHCHOP, tmc_step.x = stepperX.homing_threshold());
+ TERN_(Y_HAS_STEALTHCHOP, tmc_step.y = stepperY.homing_threshold());
+ TERN_(Z_HAS_STEALTHCHOP, tmc_step.z = stepperZ.homing_threshold());
+ #endif
+}
+
+void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleManualMove");
+
+ int16_t movevalue = swap16(*(uint16_t*)val_ptr);
+
+ // Choose Move distance
+ if (manualMoveStep == 0x01) manualMoveStep = 10;
+ else if (manualMoveStep == 0x02) manualMoveStep = 100;
+ else if (manualMoveStep == 0x03) manualMoveStep = 1000;
+
+ DEBUG_ECHOLNPGM("QUEUE LEN:", queue.ring_buffer.length);
+
+ if (!print_job_timer.isPaused() && !queue.ring_buffer.empty())
+ return;
+
+ char axiscode;
+ unsigned int speed = 1500; // FIXME: get default feedrate for manual moves, don't hardcode.
+
+ switch (var.VP) { // switch X Y Z or Home
+ default: return;
+ case VP_MOVE_X:
+ DEBUG_ECHOLNPGM("X Move");
+ axiscode = 'X';
+ if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Y:
+ DEBUG_ECHOLNPGM("Y Move");
+ axiscode = 'Y';
+ if (!ExtUI::canMove(ExtUI::axis_t::Y)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Z:
+ DEBUG_ECHOLNPGM("Z Move");
+ axiscode = 'Z';
+ speed = 300; // default to 5mm/s
+ if (!ExtUI::canMove(ExtUI::axis_t::Z)) goto cannotmove;
+ break;
+
+ case VP_MOTOR_LOCK_UNLOK:
+ DEBUG_ECHOLNPGM("Motor Unlock");
+ movevalue = 5;
+ axiscode = '\0';
+ // return ;
+ break;
+
+ case VP_HOME_ALL: // only used for homing
+ DEBUG_ECHOLNPGM("Home all");
+ axiscode = '\0';
+ movevalue = 0; // ignore value sent from display, this VP is _ONLY_ for homing.
+ //return;
+ break;
+
+ case VP_X_HOME:
+ DEBUG_ECHOLNPGM("X Home");
+ axiscode = 'X';
+ movevalue = 0;
+ break;
+
+ case VP_Y_HOME:
+ DEBUG_ECHOLNPGM("Y Home");
+ axiscode = 'Y';
+ movevalue = 0;
+ break;
+
+ case VP_Z_HOME:
+ DEBUG_ECHOLNPGM("Z Home");
+ axiscode = 'Z';
+ movevalue = 0;
+ break;
+ }
+
+ DEBUG_ECHOPGM("movevalue = ", movevalue);
+ if (movevalue != 0 && movevalue != 5) { // get move distance
+ switch (movevalue) {
+ case 0x0001: movevalue = manualMoveStep; break;
+ case 0x0002: movevalue = -manualMoveStep; break;
+ default: movevalue = 0; break;
+ }
+ }
+
+ if (!movevalue) {
+ // homing
+ DEBUG_ECHOPGM(" homing ", AS_CHAR(axiscode));
+ // char buf[6] = "G28 X";
+ // buf[4] = axiscode;
+
+ char buf[6];
+ sprintf(buf, "G28 %c", axiscode);
+ //DEBUG_ECHOPGM(" ", buf);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOLNPGM(" ✓");
+ ForceCompleteUpdate();
+ return;
+ }
+ else if (movevalue == 5) {
+ DEBUG_ECHOPGM("send M84");
+ char buf[6];
+ snprintf_P(buf,6,PSTR("M84 %c"), axiscode);
+ queue.enqueue_one_now(buf);
+ ForceCompleteUpdate();
+ return;
+ }
+ else {
+ // movement
+ DEBUG_ECHOPGM(" move ", AS_CHAR(axiscode));
+ bool old_relative_mode = relative_mode;
+
+ if (!relative_mode) {
+ //DEBUG_ECHOPGM(" G91");
+ queue.enqueue_now(F("G91"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ char buf[32]; // G1 X9999.99 F12345
+ // unsigned int backup_speed = MMS_TO_MMM(feedrate_mm_s);
+ char sign[] = "\0";
+ int16_t value = movevalue / 100;
+ if (movevalue < 0) { value = -value; sign[0] = '-'; }
+ int16_t fraction = ABS(movevalue) % 100;
+ snprintf_P(buf, 32, PSTR("G0 %c%s%d.%02d F%d"), axiscode, sign, value, fraction, speed);
+ queue.enqueue_one_now(buf);
+
+ //if (backup_speed != speed) {
+ // snprintf_P(buf, 32, PSTR("G0 F%d"), backup_speed);
+ // queue.enqueue_one_now(buf);
+ // //DEBUG_ECHOPGM(" ", buf);
+ //}
+
+ //while (!enqueue_and_echo_command(buf)) idle();
+ //DEBUG_ECHOLNPGM(" ✓ ");
+ if (!old_relative_mode) {
+ //DEBUG_ECHOPGM("G90");
+ //queue.enqueue_now(F("G90"));
+ queue.enqueue_now(F("G90"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ }
+
+ ForceCompleteUpdate();
+ DEBUG_ECHOLNPGM("manmv done.");
+ return;
+
+ cannotmove:
+ DEBUG_ECHOLNPGM(" cannot move ", AS_CHAR(axiscode));
+ return;
+}
+
+void DGUSScreenHandlerMKS::GetParkPos(DGUS_VP_Variable &var, void *val_ptr) {
+ const int16_t value_pos = swap16(*(int16_t*)val_ptr);
+
+ switch (var.VP) {
+ case VP_X_PARK_POS: mks_park_pos.x = value_pos; break;
+ case VP_Y_PARK_POS: mks_park_pos.y = value_pos; break;
+ case VP_Z_PARK_POS: mks_park_pos.z = value_pos; break;
+ default: break;
+ }
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleChangeLevelPoint(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleChangeLevelPoint");
+
+ const int16_t value_raw = swap16(*(int16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("value_raw:", value_raw);
+
+ *(int16_t*)var.memadr = value_raw;
+
+ settings.save();
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleStepPerMMChanged");
+
+ const uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ const float value = (float)value_raw;
+
+ DEBUG_ECHOLNPGM("value_raw:", value_raw);
+ DEBUG_ECHOLNPGM("value:", value);
+
+ ExtUI::axis_t axis;
+ switch (var.VP) {
+ default: return;
+ case VP_X_STEP_PER_MM: axis = ExtUI::axis_t::X; break;
+ case VP_Y_STEP_PER_MM: axis = ExtUI::axis_t::Y; break;
+ case VP_Z_STEP_PER_MM: axis = ExtUI::axis_t::Z; break;
+ }
+ ExtUI::setAxisSteps_per_mm(value, axis);
+ DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisSteps_per_mm(axis));
+ settings.save();
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleStepPerMMExtruderChanged");
+
+ const uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ const float value = (float)value_raw;
+
+ DEBUG_ECHOLNPGM("value_raw:", value_raw);
+ DEBUG_ECHOLNPGM("value:", value);
+
+ ExtUI::extruder_t extruder;
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break;
+ #endif
+ }
+ ExtUI::setAxisSteps_per_mm(value, extruder);
+ DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisSteps_per_mm(extruder));
+ settings.save();
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleMaxSpeedChange(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleMaxSpeedChange");
+
+ const uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ const float value = (float)value_raw;
+
+ DEBUG_ECHOLNPGM("value_raw:", value_raw);
+ DEBUG_ECHOLNPGM("value:", value);
+
+ ExtUI::axis_t axis;
+ switch (var.VP) {
+ case VP_X_MAX_SPEED: axis = ExtUI::axis_t::X; break;
+ case VP_Y_MAX_SPEED: axis = ExtUI::axis_t::Y; break;
+ case VP_Z_MAX_SPEED: axis = ExtUI::axis_t::Z; break;
+ default: return;
+ }
+ ExtUI::setAxisMaxFeedrate_mm_s(value, axis);
+ DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisMaxFeedrate_mm_s(axis));
+ settings.save();
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleExtruderMaxSpeedChange(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleExtruderMaxSpeedChange");
+
+ const uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ const float value = (float)value_raw;
+
+ DEBUG_ECHOLNPGM("value_raw:", value_raw);
+ DEBUG_ECHOLNPGM("value:", value);
+
+ ExtUI::extruder_t extruder;
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_MAX_SPEED: extruder = ExtUI::extruder_t::E0; break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ #endif
+ case VP_E1_MAX_SPEED: extruder = ExtUI::extruder_t::E1; break;
+ }
+ ExtUI::setAxisMaxFeedrate_mm_s(value, extruder);
+ DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisMaxFeedrate_mm_s(extruder));
+ settings.save();
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleMaxAccChange(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleMaxAccChange");
+
+ const uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ const float value = (float)value_raw;
+
+ DEBUG_ECHOLNPGM("value_raw:", value_raw);
+ DEBUG_ECHOLNPGM("value:", value);
+
+ ExtUI::axis_t axis;
+ switch (var.VP) {
+ default: return;
+ case VP_X_ACC_MAX_SPEED: axis = ExtUI::axis_t::X; break;
+ case VP_Y_ACC_MAX_SPEED: axis = ExtUI::axis_t::Y; break;
+ case VP_Z_ACC_MAX_SPEED: axis = ExtUI::axis_t::Z; break;
+ }
+ ExtUI::setAxisMaxAcceleration_mm_s2(value, axis);
+ DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisMaxAcceleration_mm_s2(axis));
+ settings.save();
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleExtruderAccChange(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleExtruderAccChange");
+
+ uint16_t value_raw = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("value_raw:", value_raw);
+ float value = (float)value_raw;
+ ExtUI::extruder_t extruder;
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_ACC_MAX_SPEED: extruder = ExtUI::extruder_t::E0; settings.load(); break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_ACC_MAX_SPEED: extruder = ExtUI::extruder_t::E1; settings.load(); break;
+ #endif
+ }
+ DEBUG_ECHOLNPGM("value:", value);
+ ExtUI::setAxisMaxAcceleration_mm_s2(value, extruder);
+ DEBUG_ECHOLNPGM("value_set:", ExtUI::getAxisMaxAcceleration_mm_s2(extruder));
+ settings.save();
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleTravelAccChange(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t value_travel = swap16(*(uint16_t*)val_ptr);
+ planner.settings.travel_acceleration = (float)value_travel;
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleFeedRateMinChange(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t value_t = swap16(*(uint16_t*)val_ptr);
+ planner.settings.min_feedrate_mm_s = (float)value_t;
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleMin_T_F(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t value_t_f = swap16(*(uint16_t*)val_ptr);
+ planner.settings.min_travel_feedrate_mm_s = (float)value_t_f;
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::HandleAccChange(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t value_acc = swap16(*(uint16_t*)val_ptr);
+ planner.settings.acceleration = (float)value_acc;
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+#if ENABLED(PREVENT_COLD_EXTRUSION)
+ void DGUSScreenHandlerMKS::HandleGetExMinTemp(DGUS_VP_Variable &var, void *val_ptr) {
+ const uint16_t value_ex_min_temp = swap16(*(uint16_t*)val_ptr);
+ thermalManager.extrude_min_temp = value_ex_min_temp;
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ }
+#endif
+
+#if HAS_PID_HEATING
+ void DGUSScreenHandler::HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ const uint16_t rawvalue = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("V1:", rawvalue);
+ const float value = 1.0f * rawvalue;
+ DEBUG_ECHOLNPGM("V2:", value);
+ float newvalue = 0;
+
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_PID_P: newvalue = value; break;
+ case VP_E0_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E0_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_PID_P: newvalue = value; break;
+ case VP_E1_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E1_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HAS_HEATED_BED
+ case VP_BED_PID_P: newvalue = value; break;
+ case VP_BED_PID_I: newvalue = scalePID_i(value); break;
+ case VP_BED_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ }
+
+ DEBUG_ECHOLNPGM("V3:", newvalue);
+ *(float *)var.memadr = newvalue;
+
+ settings.save();
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ }
+#endif // HAS_PID_HEATING
+
+#if ENABLED(BABYSTEPPING)
+ void DGUSScreenHandler::HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleLiveAdjustZ");
+ float step = ZOffset_distance;
+
+ uint16_t flag = swap16(*(uint16_t*)val_ptr);
+ switch (flag) {
+ case 0:
+ if (step == 0.01)
+ queue.inject(F("M290 Z-0.01"));
+ else if (step == 0.1)
+ queue.inject(F("M290 Z-0.1"));
+ else if (step == 0.5)
+ queue.inject(F("M290 Z-0.5"));
+ else if (step == 1)
+ queue.inject(F("M290 Z-1"));
+ else
+ queue.inject(F("M290 Z-0.01"));
+
+ z_offset_add -= ZOffset_distance;
+ break;
+
+ case 1:
+ if (step == 0.01)
+ queue.inject(F("M290 Z0.01"));
+ else if (step == 0.1)
+ queue.inject(F("M290 Z0.1"));
+ else if (step == 0.5)
+ queue.inject(F("M290 Z0.5"));
+ else if (step == 1)
+ queue.inject(F("M290 Z1"));
+ else
+ queue.inject(F("M290 Z-0.01"));
+
+ z_offset_add += ZOffset_distance;
+ break;
+
+ default:
+ break;
+ }
+ ForceCompleteUpdate();
+ }
+#endif // BABYSTEPPING
+
+void DGUSScreenHandlerMKS::GetManualFilament(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("GetManualFilament");
+
+ uint16_t value_len = swap16(*(uint16_t*)val_ptr);
+
+ float value = (float)value_len;
+
+ DEBUG_ECHOLNPGM("Get Filament len value:", value);
+ distanceFilament = value;
+
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::GetManualFilamentSpeed(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("GetManualFilamentSpeed");
+
+ uint16_t value_len = swap16(*(uint16_t*)val_ptr);
+
+ DEBUG_ECHOLNPGM("filamentSpeed_mm_s value:", value_len);
+
+ filamentSpeed_mm_s = value_len;
+
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+}
+
+void DGUSScreenHandlerMKS::FilamentLoadUnload(DGUS_VP_Variable &var, void *val_ptr, const int filamentDir) {
+ #if EITHER(HAS_MULTI_HOTEND, SINGLENOZZLE)
+ uint8_t swap_tool = 0;
+ #else
+ constexpr uint8_t swap_tool = 1; // T0 (or none at all)
+ #endif
+
+ #if HAS_HOTEND
+ uint8_t hotend_too_cold = 0;
+ #endif
+
+ if (!print_job_timer.isPaused() && !queue.ring_buffer.empty())
+ return;
+
+ const uint16_t val_t = swap16(*(uint16_t*)val_ptr);
+ switch (val_t) {
+ default: break;
+ case 0:
+ #if HAS_HOTEND
+ if (thermalManager.tooColdToExtrude(0))
+ hotend_too_cold = 1;
+ else {
+ #if EITHER(HAS_MULTI_HOTEND, SINGLENOZZLE)
+ swap_tool = 1;
+ #endif
+ }
+ #endif
+ break;
+ case 1:
+ #if HAS_MULTI_HOTEND
+ if (thermalManager.tooColdToExtrude(1)) hotend_too_cold = 2; else swap_tool = 2;
+ #elif ENABLED(SINGLENOZZLE)
+ if (thermalManager.tooColdToExtrude(0)) hotend_too_cold = 1; else swap_tool = 2;
+ #endif
+ break;
+ }
+
+ #if BOTH(HAS_HOTEND, PREVENT_COLD_EXTRUSION)
+ if (hotend_too_cold) {
+ if (thermalManager.targetTooColdToExtrude(hotend_too_cold - 1)) thermalManager.setTargetHotend(thermalManager.extrude_min_temp, hotend_too_cold - 1);
+ sendinfoscreen(F("NOTICE"), nullptr, F("Please wait."), F("Nozzle heating!"), true, true, true, true);
+ SetupConfirmAction(nullptr);
+ GotoScreen(DGUSLCD_SCREEN_POPUP);
+ }
+ #endif
+
+ if (swap_tool) {
+ char buf[30];
+ snprintf_P(buf, 30
+ #if EITHER(HAS_MULTI_HOTEND, SINGLENOZZLE)
+ , PSTR("M1002T%cE%dF%d"), char('0' + swap_tool - 1)
+ #else
+ , PSTR("M1002E%dF%d")
+ #endif
+ , (int)distanceFilament * filamentDir, filamentSpeed_mm_s * 60
+ );
+ queue.inject(buf);
+ }
+}
+
+/**
+ * M1002: Do a tool-change and relative move for FilamentLoadUnload
+ * within the G-code execution window for best concurrency.
+ */
+void GcodeSuite::M1002() {
+ #if EITHER(HAS_MULTI_HOTEND, SINGLENOZZLE)
+ {
+ char buf[3];
+ sprintf_P(buf, PSTR("T%c"), char('0' + parser.intval('T')));
+ process_subcommands_now(buf);
+ }
+ #endif
+
+ const uint8_t old_axis_relative = axis_relative;
+ set_e_relative(); // M83
+ {
+ char buf[20];
+ snprintf_P(buf, 20, PSTR("G1E%dF%d"), parser.intval('E'), parser.intval('F'));
+ process_subcommands_now(buf);
+ }
+ axis_relative = old_axis_relative;
+}
+
+void DGUSScreenHandlerMKS::FilamentLoad(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("FilamentLoad");
+ FilamentLoadUnload(var, val_ptr, 1);
+}
+
+void DGUSScreenHandlerMKS::FilamentUnLoad(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("FilamentUnLoad");
+ FilamentLoadUnload(var, val_ptr, -1);
+}
+
+#if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+
+ void DGUSScreenHandler::HandleFilamentOption(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleFilamentOption");
+
+ uint8_t e_temp = 0;
+ filament_data.heated = false;
+ uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
+ if (preheat_option >= 10) { // Unload filament type
+ preheat_option -= 10;
+ filament_data.action = 2;
+ filament_data.purge_length = DGUS_FILAMENT_PURGE_LENGTH;
+ }
+ else if (preheat_option <= 8) // Load filament type
+ filament_data.action = 1;
+ else // Cancel filament operation
+ filament_data.action = 0;
+
+ switch (preheat_option) {
+ case 0: // Load PLA
+ #ifdef PREHEAT_1_TEMP_HOTEND
+ e_temp = PREHEAT_1_TEMP_HOTEND;
+ #endif
+ break;
+ case 1: // Load ABS
+ TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND);
+ break;
+ case 2: // Load PET
+ #ifdef PREHEAT_3_TEMP_HOTEND
+ e_temp = PREHEAT_3_TEMP_HOTEND;
+ #endif
+ break;
+ case 3: // Load FLEX
+ #ifdef PREHEAT_4_TEMP_HOTEND
+ e_temp = PREHEAT_4_TEMP_HOTEND;
+ #endif
+ break;
+ case 9: // Cool down
+ default:
+ e_temp = 0;
+ break;
+ }
+
+ if (filament_data.action == 0) { // Go back to utility screen
+ #if HAS_HOTEND
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0);
+ #endif
+ #if HAS_MULTI_HOTEND
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1);
+ #endif
+ GotoScreen(DGUSLCD_SCREEN_UTILITY);
+ }
+ else { // Go to the preheat screen to show the heating progress
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E0;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E1;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ }
+ }
+ }
+
+ void DGUSScreenHandler::HandleFilamentLoadUnload(DGUS_VP_Variable &var) {
+ DEBUG_ECHOLNPGM("HandleFilamentLoadUnload");
+ if (filament_data.action <= 0) return;
+
+ // If we close to the target temperature, we can start load or unload the filament
+ if (thermalManager.hotEnoughToExtrude(filament_data.extruder) && \
+ thermalManager.targetHotEnoughToExtrude(filament_data.extruder)) {
+ float movevalue = DGUS_FILAMENT_LOAD_LENGTH_PER_TIME;
+
+ if (filament_data.action == 1) { // load filament
+ if (!filament_data.heated) {
+ filament_data.heated = true;
+ }
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
+ }
+ else { // unload filament
+ if (!filament_data.heated) {
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_UNLOADING);
+ filament_data.heated = true;
+ }
+ // Before unloading extrude to prevent jamming
+ if (filament_data.purge_length >= 0) {
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
+ filament_data.purge_length -= movevalue;
+ }
+ else {
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue;
+ }
+ }
+ ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder);
+ }
+ }
+
+#endif // DGUS_FILAMENT_LOADUNLOAD
+
+bool DGUSScreenHandlerMKS::loop() {
+ dgusdisplay.loop();
+
+ const millis_t ms = millis();
+ static millis_t next_event_ms = 0;
+
+ static uint8_t language_times = 2;
+
+ if (!IsScreenComplete() || ELAPSED(ms, next_event_ms)) {
+ next_event_ms = ms + DGUS_UPDATE_INTERVAL_MS;
+ UpdateScreenVPData();
+ }
+
+ if (language_times != 0) {
+ LanguagePInit();
+ DGUS_LanguageDisplay(mks_language_index);
+ language_times--;
+ }
+
+ #if ENABLED(SHOW_BOOTSCREEN)
+ static bool booted = false;
+ if (!booted && ELAPSED(ms, TERN(USE_MKS_GREEN_UI, 1000, BOOTSCREEN_TIMEOUT))) {
+ booted = true;
+ #if USE_SENSORLESS
+ TERN_(X_HAS_STEALTHCHOP, tmc_step.x = stepperX.homing_threshold());
+ TERN_(Y_HAS_STEALTHCHOP, tmc_step.y = stepperY.homing_threshold());
+ TERN_(Z_HAS_STEALTHCHOP, tmc_step.z = stepperZ.homing_threshold());
+ #endif
+
+ #if ENABLED(PREVENT_COLD_EXTRUSION)
+ if (mks_min_extrusion_temp != 0)
+ thermalManager.extrude_min_temp = mks_min_extrusion_temp;
+ #endif
+
+ DGUS_ExtrudeLoadInit();
+
+ TERN_(DGUS_MKS_RUNOUT_SENSOR, DGUS_RunoutInit());
+
+ if (TERN0(POWER_LOSS_RECOVERY, recovery.valid()))
+ GotoScreen(DGUSLCD_SCREEN_POWER_LOSS);
+ else
+ GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+
+ #if ENABLED(DGUS_MKS_RUNOUT_SENSOR)
+ if (booted && printingIsActive()) DGUS_Runout_Idle();
+ #endif
+ #endif // SHOW_BOOTSCREEN
+
+ return IsScreenComplete();
+}
+
+void DGUSScreenHandlerMKS::LanguagePInit() {
+ switch (mks_language_index) {
+ case MKS_SimpleChinese:
+ dgusdisplay.WriteVariable(VP_LANGUAGE_CHANGE1, (uint8_t)MKS_Language_Choose);
+ dgusdisplay.WriteVariable(VP_LANGUAGE_CHANGE2, (uint8_t)MKS_Language_NoChoose);
+ break;
+ case MKS_English:
+ dgusdisplay.WriteVariable(VP_LANGUAGE_CHANGE1, (uint8_t)MKS_Language_NoChoose);
+ dgusdisplay.WriteVariable(VP_LANGUAGE_CHANGE2, (uint8_t)MKS_Language_Choose);
+ break;
+ default:
+ break;
+ }
+}
+
+void DGUSScreenHandlerMKS::DGUS_ExtrudeLoadInit() {
+ ex_filament.ex_length = distanceFilament;
+ ex_filament.ex_load_unload_flag = 0;
+ ex_filament.ex_need_time = filamentSpeed_mm_s;
+ ex_filament.ex_speed = 0;
+ ex_filament.ex_status = EX_NONE;
+ ex_filament.ex_tick_end = 0;
+ ex_filament.ex_tick_start = 0;
+}
+
+void DGUSScreenHandlerMKS::DGUS_RunoutInit() {
+ #if PIN_EXISTS(MT_DET_1)
+ SET_INPUT_PULLUP(MT_DET_1_PIN);
+ #endif
+ runout_mks.de_count = 0;
+ runout_mks.de_times = 10;
+ runout_mks.pin_status = 1;
+ runout_mks.runout_status = UNRUNOUT_STATUS;
+}
+
+void DGUSScreenHandlerMKS::DGUS_Runout_Idle() {
+ #if ENABLED(DGUS_MKS_RUNOUT_SENSOR)
+ // scanf runout pin
+ switch (runout_mks.runout_status) {
+
+ case RUNOUT_STATUS:
+ runout_mks.runout_status = RUNOUT_BEGIN_STATUS;
+ queue.inject(F("M25"));
+ GotoScreen(MKSLCD_SCREEN_PAUSE);
+
+ sendinfoscreen(F("NOTICE"), nullptr, F("Please change filament!"), nullptr, true, true, true, true);
+ //SetupConfirmAction(nullptr);
+ GotoScreen(DGUSLCD_SCREEN_POPUP);
+ break;
+
+ case UNRUNOUT_STATUS:
+ if (READ(MT_DET_1_PIN) == MT_DET_PIN_STATE)
+ runout_mks.runout_status = RUNOUT_STATUS;
+ break;
+
+ case RUNOUT_BEGIN_STATUS:
+ if (READ(MT_DET_1_PIN) != MT_DET_PIN_STATE)
+ runout_mks.runout_status = RUNOUT_WAITING_STATUS;
+ break;
+
+ case RUNOUT_WAITING_STATUS:
+ if (READ(MT_DET_1_PIN) == MT_DET_PIN_STATE)
+ runout_mks.runout_status = RUNOUT_BEGIN_STATUS;
+ break;
+
+ default: break;
+ }
+ #endif
+}
+
+void DGUSScreenHandlerMKS::DGUS_LanguageDisplay(uint8_t var) {
+ if (var == MKS_English) {
+ const char home_buf_en[] = "Home";
+ dgusdisplay.WriteVariable(VP_HOME_Dis, home_buf_en, 32, true);
+
+ const char setting_buf_en[] = "Setting";
+ dgusdisplay.WriteVariable(VP_Setting_Dis, setting_buf_en, 32, true);
+
+ const char Tool_buf_en[] = "Tool";
+ dgusdisplay.WriteVariable(VP_Tool_Dis, Tool_buf_en, 32, true);
+
+ const char Print_buf_en[] = "Print";
+ dgusdisplay.WriteVariable(VP_Print_Dis, Print_buf_en, 32, true);
+
+ const char Language_buf_en[] = "Language";
+ dgusdisplay.WriteVariable(VP_Language_Dis, Language_buf_en, 32, true);
+
+ const char About_buf_en[] = "About";
+ dgusdisplay.WriteVariable(VP_About_Dis, About_buf_en, 32, true);
+
+ const char Config_buf_en[] = "Config";
+ dgusdisplay.WriteVariable(VP_Config_Dis, Config_buf_en, 32, true);
+
+ const char MotorConfig_buf_en[] = "MotorConfig";
+ dgusdisplay.WriteVariable(VP_MotorConfig_Dis, MotorConfig_buf_en, 32, true);
+
+ const char LevelConfig_buf_en[] = "LevelConfig";
+ dgusdisplay.WriteVariable(VP_LevelConfig_Dis, LevelConfig_buf_en, 32, true);
+
+ const char TemperatureConfig_buf_en[] = "Temperature";
+ dgusdisplay.WriteVariable(VP_TemperatureConfig_Dis, TemperatureConfig_buf_en, 32, true);
+
+ const char Advance_buf_en[] = "Advance";
+ dgusdisplay.WriteVariable(VP_Advance_Dis, Advance_buf_en, 32, true);
+
+ const char Filament_buf_en[] = "Extrude";
+ dgusdisplay.WriteVariable(VP_Filament_Dis, Filament_buf_en, 32, true);
+
+ const char Move_buf_en[] = "Move";
+ dgusdisplay.WriteVariable(VP_Move_Dis, Move_buf_en, 32, true);
+
+ #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
+ const char Level_buf_en[] = "AutoLevel";
+ dgusdisplay.WriteVariable(VP_Level_Dis, Level_buf_en, 32, true);
+ #elif ENABLED(MESH_BED_LEVELING)
+ const char Level_buf_en[] = "MeshLevel";
+ dgusdisplay.WriteVariable(VP_Level_Dis, Level_buf_en, 32, true);
+ #else
+ const char Level_buf_en[] = "Level";
+ dgusdisplay.WriteVariable(VP_Level_Dis, Level_buf_en, 32, true);
+ #endif
+
+ const char MotorPluse_buf_en[] = "MotorPluse";
+ dgusdisplay.WriteVariable(VP_MotorPluse_Dis, MotorPluse_buf_en, 32, true);
+
+ const char MotorMaxSpeed_buf_en[] = "MotorMaxSpeed";
+ dgusdisplay.WriteVariable(VP_MotorMaxSpeed_Dis, MotorMaxSpeed_buf_en, 32, true);
+
+ const char MotorMaxAcc_buf_en[] = "MotorAcc";
+ dgusdisplay.WriteVariable(VP_MotorMaxAcc_Dis, MotorMaxAcc_buf_en, 32, true);
+
+ const char TravelAcc_buf_en[] = "TravelAcc";
+ dgusdisplay.WriteVariable(VP_TravelAcc_Dis, TravelAcc_buf_en, 32, true);
+
+ const char FeedRateMin_buf_en[] = "FeedRateMin";
+ dgusdisplay.WriteVariable(VP_FeedRateMin_Dis, FeedRateMin_buf_en, 32, true);
+
+ const char TravelFeeRateMin_buf_en[] = "TravelFeedRateMin";
+ dgusdisplay.WriteVariable(VP_TravelFeeRateMin_Dis, TravelFeeRateMin_buf_en, 32, true);
+
+ const char Acc_buf_en[] = "Acc";
+ dgusdisplay.WriteVariable(VP_ACC_Dis, Acc_buf_en, 32, true);
+
+ const char Point_One_buf_en[] = "Point_First";
+ dgusdisplay.WriteVariable(VP_Point_One_Dis, Point_One_buf_en, 32, true);
+
+ const char Point_Two_buf_en[] = "Point_Second";
+ dgusdisplay.WriteVariable(VP_Point_Two_Dis, Point_Two_buf_en, 32, true);
+
+ const char Point_Three_buf_en[] = "Point_Third";
+ dgusdisplay.WriteVariable(VP_Point_Three_Dis, Point_Three_buf_en, 32, true);
+
+ const char Point_Four_buf_en[] = "Point_Fourth";
+ dgusdisplay.WriteVariable(VP_Point_Four_Dis, Point_Four_buf_en, 32, true);
+
+ const char Point_Five_buf_en[] = "Point_Fifth";
+ dgusdisplay.WriteVariable(VP_Point_Five_Dis, Point_Five_buf_en, 32, true);
+
+ const char Extrusion_buf_en[] = "Extrusion";
+ dgusdisplay.WriteVariable(VP_Extrusion_Dis, Extrusion_buf_en, 32, true);
+
+ const char HeatBed_buf_en[] = "HeatBed";
+ dgusdisplay.WriteVariable(VP_HeatBed_Dis, HeatBed_buf_en, 32, true);
+
+ const char FactoryDefaults_buf_en[] = "FactoryDefaults";
+ dgusdisplay.WriteVariable(VP_FactoryDefaults_Dis, FactoryDefaults_buf_en, 32, true);
+
+ const char StoreSetting_buf_en[] = "StoreSetting";
+ dgusdisplay.WriteVariable(VP_StoreSetting_Dis, StoreSetting_buf_en, 32, true);
+
+ const char PrintPauseConfig_buf_en[] = "PrintPauseConfig";
+ dgusdisplay.WriteVariable(VP_PrintPauseConfig_Dis, PrintPauseConfig_buf_en, 32, true);
+
+ const char X_Pluse_buf_en[] = "X_Pluse";
+ dgusdisplay.WriteVariable(VP_X_Pluse_Dis, X_Pluse_buf_en, 32, true);
+
+ const char Y_Pluse_buf_en[] = "Y_Pluse";
+ dgusdisplay.WriteVariable(VP_Y_Pluse_Dis, Y_Pluse_buf_en, 32, true);
+
+ const char Z_Pluse_buf_en[] = "Z_Pluse";
+ dgusdisplay.WriteVariable(VP_Z_Pluse_Dis, Z_Pluse_buf_en, 32, true);
+
+ const char E0_Pluse_buf_en[] = "E0_Pluse";
+ dgusdisplay.WriteVariable(VP_E0_Pluse_Dis, E0_Pluse_buf_en, 32, true);
+
+ const char E1_Pluse_buf_en[] = "E1_Pluse";
+ dgusdisplay.WriteVariable(VP_E1_Pluse_Dis, E1_Pluse_buf_en, 32, true);
+
+ const char X_Max_Speed_buf_en[] = "X_Max_Speed";
+ dgusdisplay.WriteVariable(VP_X_Max_Speed_Dis, X_Max_Speed_buf_en, 32, true);
+
+ const char Y_Max_Speed_buf_en[] = "Y_Max_Speed";
+ dgusdisplay.WriteVariable(VP_Y_Max_Speed_Dis, Y_Max_Speed_buf_en, 32, true);
+
+ const char Z_Max_Speed_buf_en[] = "Z_Max_Speed";
+ dgusdisplay.WriteVariable(VP_Z_Max_Speed_Dis, Z_Max_Speed_buf_en, 32, true);
+
+ const char E0_Max_Speed_buf_en[] = "E0_Max_Speed";
+ dgusdisplay.WriteVariable(VP_E0_Max_Speed_Dis, E0_Max_Speed_buf_en, 32, true);
+
+ const char E1_Max_Speed_buf_en[] = "E1_Max_Speed";
+ dgusdisplay.WriteVariable(VP_E1_Max_Speed_Dis, E1_Max_Speed_buf_en, 32, true);
+
+ const char X_Max_Acc_Speed_buf_en[] = "X_Max_Acc_Speed";
+ dgusdisplay.WriteVariable(VP_X_Max_Acc_Speed_Dis, X_Max_Acc_Speed_buf_en, 32, true);
+
+ const char Y_Max_Acc_Speed_buf_en[] = "Y_Max_Acc_Speed";
+ dgusdisplay.WriteVariable(VP_Y_Max_Acc_Speed_Dis, Y_Max_Acc_Speed_buf_en, 32, true);
+
+ const char Z_Max_Acc_Speed_buf_en[] = "Z_Max_Acc_Speed";
+ dgusdisplay.WriteVariable(VP_Z_Max_Acc_Speed_Dis, Z_Max_Acc_Speed_buf_en, 32, true);
+
+ const char E0_Max_Acc_Speed_buf_en[] = "E0_Max_Acc_Speed";
+ dgusdisplay.WriteVariable(VP_E0_Max_Acc_Speed_Dis, E0_Max_Acc_Speed_buf_en, 32, true);
+
+ const char E1_Max_Acc_Speed_buf_en[] = "E1_Max_Acc_Speed";
+ dgusdisplay.WriteVariable(VP_E1_Max_Acc_Speed_Dis, E1_Max_Acc_Speed_buf_en, 32, true);
+
+ const char X_PARK_POS_buf_en[] = "X_PARK_POS";
+ dgusdisplay.WriteVariable(VP_X_PARK_POS_Dis, X_PARK_POS_buf_en, 32, true);
+
+ const char Y_PARK_POS_buf_en[] = "Y_PARK_POS";
+ dgusdisplay.WriteVariable(VP_Y_PARK_POS_Dis, Y_PARK_POS_buf_en, 32, true);
+
+ const char Z_PARK_POS_buf_en[] = "Z_PARK_POS";
+ dgusdisplay.WriteVariable(VP_Z_PARK_POS_Dis, Z_PARK_POS_buf_en, 32, true);
+
+ const char Length_buf_en[] = "Length";
+ dgusdisplay.WriteVariable(VP_Length_Dis, Length_buf_en, 32, true);
+
+ const char Speed_buf_en[] = "Speed";
+ dgusdisplay.WriteVariable(VP_Speed_Dis, Speed_buf_en, 32, true);
+
+ const char InOut_buf_en[] = "InOut";
+ dgusdisplay.WriteVariable(VP_InOut_Dis, InOut_buf_en, 32, true);
+
+ const char PrintTimet_buf_en[] = "PrintTime";
+ dgusdisplay.WriteVariable(VP_PrintTime_Dis, PrintTimet_buf_en, 32, true);
+
+ const char E0_Temp_buf_en[] = "E0_Temp";
+ dgusdisplay.WriteVariable(VP_E0_Temp_Dis, E0_Temp_buf_en, 32, true);
+
+ const char E1_Temp_buf_en[] = "E1_Temp";
+ dgusdisplay.WriteVariable(VP_E1_Temp_Dis, E1_Temp_buf_en, 32, true);
+
+ const char HB_Temp_buf_en[] = "HB_Temp";
+ dgusdisplay.WriteVariable(VP_HB_Temp_Dis, HB_Temp_buf_en, 32, true);
+
+ const char Feedrate_buf_en[] = "Feedrate";
+ dgusdisplay.WriteVariable(VP_Feedrate_Dis, Feedrate_buf_en, 32, true);
+
+ const char PrintAcc_buf_en[] = "PrintSpeed";
+ dgusdisplay.WriteVariable(VP_PrintAcc_Dis, PrintAcc_buf_en, 32, true);
+
+ const char FAN_Speed_buf_en[] = "FAN_Speed";
+ dgusdisplay.WriteVariable(VP_Fan_Speed_Dis, FAN_Speed_buf_en, 32, true);
+
+ const char Printing_buf_en[] = "Printing";
+ dgusdisplay.WriteVariable(VP_Printing_Dis, Printing_buf_en, 32, true);
+
+ const char Info_EEPROM_1_buf_en[] = "Store setting?";
+ dgusdisplay.WriteVariable(VP_Info_EEPROM_1_Dis, Info_EEPROM_1_buf_en, 32, true);
+
+ const char Info_EEPROM_2_buf_en[] = "Revert setting?";
+ dgusdisplay.WriteVariable(VP_Info_EEPROM_2_Dis, Info_EEPROM_2_buf_en, 32, true);
+
+ const char Info_PrintFinish_1_buf_en[] = "Print Done";
+ dgusdisplay.WriteVariable(VP_Info_PrintFinish_1_Dis, Info_PrintFinish_1_buf_en, 32, true);
+
+ const char TMC_X_Step_buf_en[] = "X_SenSitivity";
+ dgusdisplay.WriteVariable(VP_TMC_X_Step_Dis, TMC_X_Step_buf_en, 32, true);
+
+ const char TMC_Y_Step_buf_en[] = "Y_SenSitivity";
+ dgusdisplay.WriteVariable(VP_TMC_Y_Step_Dis, TMC_Y_Step_buf_en, 32, true);
+
+ const char TMC_Z_Step_buf_en[] = "Z_SenSitivity";
+ dgusdisplay.WriteVariable(VP_TMC_Z_Step_Dis, TMC_Z_Step_buf_en, 32, true);
+
+ const char TMC_X_Current_buf_en[] = "X_Current";
+ dgusdisplay.WriteVariable(VP_TMC_X_Current_Dis, TMC_X_Current_buf_en, 32, true);
+
+ const char TMC_Y_Current_buf_en[] = "Y_Current";
+ dgusdisplay.WriteVariable(VP_TMC_Y_Current_Dis, TMC_Y_Current_buf_en, 32, true);
+
+ const char TMC_Z_Current_buf_en[] = "Z_Current";
+ dgusdisplay.WriteVariable(VP_TMC_Z_Current_Dis, TMC_Z_Current_buf_en, 32, true);
+
+ const char TMC_E0_Current_buf_en[] = "E0_Current";
+ dgusdisplay.WriteVariable(VP_TMC_E0_Current_Dis, TMC_E0_Current_buf_en, 32, true);
+
+ const char TMC_X1_Current_buf_en[] = "X1_Current";
+ dgusdisplay.WriteVariable(VP_TMC_X1_Current_Dis, TMC_X1_Current_buf_en, 32, true);
+
+ const char TMC_Y1_Current_buf_en[] = "Y1_Current";
+ dgusdisplay.WriteVariable(VP_TMC_Y1_Current_Dis, TMC_Y1_Current_buf_en, 32, true);
+
+ const char TMC_Z1_Current_buf_en[] = "Z1_Current";
+ dgusdisplay.WriteVariable(VP_TMC_Z1_Current_Dis, TMC_Z1_Current_buf_en, 32, true);
+
+ const char TMC_E1_Current_buf_en[] = "E1_Current";
+ dgusdisplay.WriteVariable(VP_TMC_E1_Current_Dis, TMC_E1_Current_buf_en, 32, true);
+
+ const char Min_Ex_Temp_buf_en[] = "Min_Ex_Temp";
+ dgusdisplay.WriteVariable(VP_Min_Ex_Temp_Dis, Min_Ex_Temp_buf_en, 32, true);
+
+ const char AutoLEVEL_INFO1_buf_en[] = "Please Press Button!";
+ dgusdisplay.WriteVariable(VP_AutoLEVEL_INFO1, AutoLEVEL_INFO1_buf_en, 32, true);
+
+ const char EX_TEMP_INFO2_buf_en[] = "Please wait a monent";
+ dgusdisplay.WriteVariable(VP_EX_TEMP_INFO2_Dis, EX_TEMP_INFO2_buf_en, 32, true);
+
+ const char EX_TEMP_INFO3_buf_en[] = "Cancle";
+ dgusdisplay.WriteVariable(VP_EX_TEMP_INFO3_Dis, EX_TEMP_INFO3_buf_en, 32, true);
+
+ const char PrintConfrim_Info_buf_en[] = "Start Print?";
+ dgusdisplay.WriteVariable(VP_PrintConfrim_Info_Dis, PrintConfrim_Info_buf_en, 32, true);
+
+ const char StopPrintConfrim_Info_buf_en[] = "Stop Print?";
+ dgusdisplay.WriteVariable(VP_StopPrintConfrim_Info_Dis, StopPrintConfrim_Info_buf_en, 32, true);
+
+ const char Printting_buf_en[] = "Printing";
+ dgusdisplay.WriteVariable(VP_Printting_Dis, Printting_buf_en, 32, true);
+
+ const char LCD_BLK_buf_en[] = "Backlight";
+ dgusdisplay.WriteVariable(VP_LCD_BLK_Dis, LCD_BLK_buf_en, 32, true);
+ }
+ else if (var == MKS_SimpleChinese) {
+ uint16_t home_buf_ch[] = { 0xF7D6, 0xB3D2 };
+ dgusdisplay.WriteVariable(VP_HOME_Dis, home_buf_ch, 4, true);
+
+ const uint16_t Setting_Dis[] = { 0xE8C9, 0xC3D6, 0x2000, 0x2000, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Setting_Dis, Setting_Dis, 7, true);
+
+ const uint16_t Tool_Dis[] = { 0xA4B9, 0xDFBE };
+ dgusdisplay.WriteVariable(VP_Tool_Dis, Tool_Dis, 4, true);
+
+ const uint16_t Print_buf_ch[] = { 0xF2B4, 0xA1D3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Print_Dis, Print_buf_ch, 6, true);
+
+ const uint16_t Language_buf_ch[] = { 0xEFD3, 0xD4D1, 0x2000, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Language_Dis, Language_buf_ch, 8, true);
+
+ const uint16_t About_buf_ch[] = { 0xD8B9, 0xDAD3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_About_Dis, About_buf_ch, 6, true);
+
+ const uint16_t Config_buf_ch[] = { 0xE4C5, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Config_Dis, Config_buf_ch, 6, true);
+
+ const uint16_t MotorConfig_buf_ch[] = { 0xE7B5, 0xFABB, 0xE4C5, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_MotorConfig_Dis, MotorConfig_buf_ch, 12, true);
+
+ const uint16_t LevelConfig_buf_ch[] = { 0xD6CA, 0xAFB6, 0xF7B5, 0xBDC6, 0xE8C9, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_LevelConfig_Dis, LevelConfig_buf_ch, 32, true);
+
+ const uint16_t TemperatureConfig_buf_ch[] = { 0xC2CE, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TemperatureConfig_Dis, TemperatureConfig_buf_ch, 11, true);
+
+ const uint16_t Advance_buf_ch[] = { 0xDFB8, 0xB6BC, 0xE8C9, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Advance_Dis, Advance_buf_ch, 16, true);
+
+ const uint16_t Filament_buf_ch[] = { 0xB7BC, 0xF6B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Filament_Dis, Filament_buf_ch, 8, true);
+
+ const uint16_t Move_buf_ch[] = { 0xC6D2, 0xAFB6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Move_Dis, Move_buf_ch, 4, true);
+
+ #if ENABLED(AUTO_BED_LEVELING_BILINEAR)
+ const uint16_t Level_buf_ch[] = { 0xD4D7, 0xAFB6, 0xF7B5, 0xBDC6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Level_Dis, Level_buf_ch, 32, true);
+ #elif ENABLED(MESH_BED_LEVELING)
+ const uint16_t Level_buf_ch[] = { 0xF8CD, 0xF1B8, 0xF7B5, 0xBDC6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Level_Dis, Level_buf_ch, 32, true);
+ #else
+ const uint16_t Level_buf_ch[] = { 0xD6CA, 0xAFB6, 0xF7B5, 0xBDC6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Level_Dis, Level_buf_ch, 32, true);
+ #endif
+
+ const uint16_t MotorPluse_buf_ch[] = { 0xF6C2, 0xE5B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_MotorPluse_Dis, MotorPluse_buf_ch, 16, true);
+
+ const uint16_t MotorMaxSpeed_buf_ch[] = { 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_MotorMaxSpeed_Dis, MotorMaxSpeed_buf_ch, 16, true);
+
+ const uint16_t MotorMaxAcc_buf_ch[] = { 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_MotorMaxAcc_Dis, MotorMaxAcc_buf_ch, 16, true);
+
+ const uint16_t TravelAcc_buf_ch[] = { 0xD5BF, 0xD0D0, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TravelAcc_Dis, TravelAcc_buf_ch, 16, true);
+
+ const uint16_t FeedRateMin_buf_ch[] = { 0xEED7, 0xA1D0, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_FeedRateMin_Dis, FeedRateMin_buf_ch, 12, true);
+
+ const uint16_t TravelFeeRateMin_buf_ch[] = { 0xD5BF, 0xD0D0, 0xEED7, 0xA1D0, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TravelFeeRateMin_Dis, TravelFeeRateMin_buf_ch, 24, true);
+
+ const uint16_t Acc_buf_ch[] = { 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_ACC_Dis, Acc_buf_ch, 16, true);
+
+ const uint16_t Point_One_buf_ch[] = { 0xDAB5, 0xBBD2, 0xE3B5, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Point_One_Dis, Point_One_buf_ch, 12, true);
+
+ const uint16_t Point_Two_buf_ch[] = { 0xDAB5, 0xFEB6, 0xE3B5, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Point_Two_Dis, Point_Two_buf_ch, 12, true);
+
+ const uint16_t Point_Three_buf_ch[] = { 0xDAB5, 0xFDC8, 0xE3B5, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Point_Three_Dis, Point_Three_buf_ch, 12, true);
+
+ const uint16_t Point_Four_buf_ch[] = { 0xDAB5, 0xC4CB, 0xE3B5, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Point_Four_Dis, Point_Four_buf_ch, 12, true);
+
+ const uint16_t Point_Five_buf_ch[] = { 0xDAB5, 0xE5CE, 0xE3B5, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Point_Five_Dis, Point_Five_buf_ch, 12, true);
+
+ const uint16_t Extrusion_buf_ch[] = { 0xB7BC, 0xF6B3, 0xB7CD, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Extrusion_Dis, Extrusion_buf_ch, 12, true);
+
+ const uint16_t HeatBed_buf_ch[] = { 0xC8C8, 0xB2B4, 0x2000 };
+ dgusdisplay.WriteVariable(VP_HeatBed_Dis, HeatBed_buf_ch, 12, true);
+
+ const uint16_t FactoryDefaults_buf_ch[] = { 0xD6BB, 0xB4B8, 0xF6B3, 0xA7B3, 0xE8C9, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_FactoryDefaults_Dis, FactoryDefaults_buf_ch, 16, true);
+
+ const uint16_t StoreSetting_buf_ch[] = { 0xA3B1, 0xE6B4, 0xE8C9, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_StoreSetting_Dis, StoreSetting_buf_ch, 16, true);
+
+ const uint16_t PrintPauseConfig_buf_ch[] = { 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_PrintPauseConfig_Dis, PrintPauseConfig_buf_ch, 32, true);
+
+ const uint16_t X_Pluse_buf_ch[] = { 0x2058, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_X_Pluse_Dis, X_Pluse_buf_ch, 16, true);
+
+ const uint16_t Y_Pluse_buf_ch[] = { 0x2059, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Y_Pluse_Dis, Y_Pluse_buf_ch, 16, true);
+
+ const uint16_t Z_Pluse_buf_ch[] = { 0x205A, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Z_Pluse_Dis, Z_Pluse_buf_ch, 16, true);
+
+ const uint16_t E0_Pluse_buf_ch[] = { 0x3045, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_E0_Pluse_Dis, E0_Pluse_buf_ch, 16, true);
+
+ const uint16_t E1_Pluse_buf_ch[] = { 0x3145, 0xE1D6, 0xF6C2, 0xE5B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_E1_Pluse_Dis, E1_Pluse_buf_ch, 16, true);
+
+ const uint16_t X_Max_Speed_buf_ch[] = { 0x2058, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_X_Max_Speed_Dis, X_Max_Speed_buf_ch, 16, true);
+
+ const uint16_t Y_Max_Speed_buf_ch[] = { 0x2059, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Y_Max_Speed_Dis, Y_Max_Speed_buf_ch, 16, true);
+
+ const uint16_t Z_Max_Speed_buf_ch[] = { 0x205A, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Z_Max_Speed_Dis, Z_Max_Speed_buf_ch, 16, true);
+
+ const uint16_t E0_Max_Speed_buf_ch[] = { 0x3045, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_E0_Max_Speed_Dis, E0_Max_Speed_buf_ch, 16, true);
+
+ const uint16_t E1_Max_Speed_buf_ch[] = { 0x3145, 0xEED7, 0xF3B4, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_E1_Max_Speed_Dis, E1_Max_Speed_buf_ch, 16, true);
+
+ const uint16_t X_Max_Acc_Speed_buf_ch[] = { 0x2058, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_X_Max_Acc_Speed_Dis, X_Max_Acc_Speed_buf_ch, 16, true);
+
+ const uint16_t Y_Max_Acc_Speed_buf_ch[] = { 0x2059, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Y_Max_Acc_Speed_Dis, Y_Max_Acc_Speed_buf_ch, 16, true);
+
+ const uint16_t Z_Max_Acc_Speed_buf_ch[] = { 0x205A, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Z_Max_Acc_Speed_Dis, Z_Max_Acc_Speed_buf_ch, 16, true);
+
+ const uint16_t E0_Max_Acc_Speed_buf_ch[] = { 0x3045, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_E0_Max_Acc_Speed_Dis, E0_Max_Acc_Speed_buf_ch, 16, true);
+
+ const uint16_t E1_Max_Acc_Speed_buf_ch[] = { 0x3145, 0xEED7, 0xF3B4, 0xD3BC, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_E1_Max_Acc_Speed_Dis, E1_Max_Acc_Speed_buf_ch, 16, true);
+
+ const uint16_t X_PARK_POS_buf_ch[] = { 0x2058, 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_X_PARK_POS_Dis, X_PARK_POS_buf_ch, 16, true);
+
+ const uint16_t Y_PARK_POS_buf_ch[] = { 0x2059, 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Y_PARK_POS_Dis, Y_PARK_POS_buf_ch, 16, true);
+
+ const uint16_t Z_PARK_POS_buf_ch[] = { 0x205A, 0xDDD4, 0xA3CD, 0xBBCE, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Z_PARK_POS_Dis, Z_PARK_POS_buf_ch, 16, true);
+
+ const uint16_t Length_buf_ch[] = { 0xBDB2, 0xA4B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Length_Dis, Length_buf_ch, 8, true);
+
+ const uint16_t Speed_buf_ch[] = { 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Speed_Dis, Speed_buf_ch, 8, true);
+
+ const uint16_t InOut_buf_ch[] = { 0xF8BD, 0xF6B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_InOut_Dis, InOut_buf_ch, 8, true);
+
+ const uint16_t PrintTimet_buf_en[] = { 0xF2B4, 0xA1D3, 0xB1CA, 0xE4BC, 0x2000 };
+ dgusdisplay.WriteVariable(VP_PrintTime_Dis, PrintTimet_buf_en, 16, true);
+
+ const uint16_t E0_Temp_buf_ch[] = { 0x3045, 0xC2CE, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_E0_Temp_Dis, E0_Temp_buf_ch, 16, true);
+
+ const uint16_t E1_Temp_buf_ch[] = { 0x3145, 0xC2CE, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_E1_Temp_Dis, E1_Temp_buf_ch, 16, true);
+
+ const uint16_t HB_Temp_buf_ch[] = { 0xC8C8, 0xB2B4, 0xC2CE, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_HB_Temp_Dis, HB_Temp_buf_ch, 16, true);
+
+ const uint16_t Feedrate_buf_ch[] = { 0xB7BC, 0xF6B3, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Feedrate_Dis, Feedrate_buf_ch, 16, true);
+
+ const uint16_t PrintAcc_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_PrintAcc_Dis, PrintAcc_buf_ch, 16, true);
+
+ const uint16_t FAN_Speed_buf_ch[] = { 0xE7B7, 0xC8C9, 0xD9CB, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Fan_Speed_Dis, FAN_Speed_buf_ch, 16, true);
+
+ const uint16_t Printing_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD0D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Printing_Dis, Printing_buf_ch, 16, true);
+
+ const uint16_t Info_EEPROM_1_buf_ch[] = { 0xC7CA, 0xF1B7, 0xA3B1, 0xE6B4, 0xE8C9, 0xC3D6, 0xBFA3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Info_EEPROM_1_Dis, Info_EEPROM_1_buf_ch, 32, true);
+
+ const uint16_t Info_EEPROM_2_buf_ch[] = { 0xC7CA, 0xF1B7, 0xD6BB, 0xB4B8, 0xF6B3, 0xA7B3, 0xE8C9, 0xC3D6, 0xBFA3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Info_EEPROM_2_Dis, Info_EEPROM_2_buf_ch, 32, true);
+
+ const uint16_t TMC_X_Step_buf_ch[] = { 0x2058, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_X_Step_Dis, TMC_X_Step_buf_ch, 16, true);
+
+ const uint16_t TMC_Y_Step_buf_ch[] = { 0x2059, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_Y_Step_Dis, TMC_Y_Step_buf_ch, 16, true);
+
+ const uint16_t TMC_Z_Step_buf_ch[] = { 0x205A, 0xE9C1, 0xF4C3, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_Z_Step_Dis, TMC_Z_Step_buf_ch, 16, true);
+
+ const uint16_t Info_PrintFinish_1_buf_ch[] = { 0xF2B4, 0xA1D3, 0xEACD, 0xC9B3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Info_PrintFinish_1_Dis, Info_PrintFinish_1_buf_ch, 32, true);
+
+ const uint16_t TMC_X_Current_buf_ch[] = { 0x2058, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_X_Current_Dis, TMC_X_Current_buf_ch, 16, true);
+
+ const uint16_t TMC_Y_Current_buf_ch[] = { 0x2059, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_Y_Current_Dis, TMC_Y_Current_buf_ch, 16, true);
+
+ const uint16_t TMC_Z_Current_buf_ch[] = { 0x205A, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_Z_Current_Dis, TMC_Z_Current_buf_ch, 16, true);
+
+ const uint16_t TMC_E0_Current_buf_ch[] = { 0x3045, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_E0_Current_Dis, TMC_E0_Current_buf_ch, 16, true);
+
+ const uint16_t TMC_X1_Current_buf_ch[] = { 0x3158, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_X1_Current_Dis, TMC_X1_Current_buf_ch, 16, true);
+
+ const uint16_t TMC_Y1_Current_buf_ch[] = { 0x3159, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_Y1_Current_Dis, TMC_Y1_Current_buf_ch, 16, true);
+
+ const uint16_t TMC_Z1_Current_buf_ch[] = { 0x315A, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_Z1_Current_Dis, TMC_Z1_Current_buf_ch, 16, true);
+
+ const uint16_t TMC_E1_Current_buf_ch[] = { 0x3145, 0xE1D6, 0xE7B5, 0xF7C1, 0x2000 };
+ dgusdisplay.WriteVariable(VP_TMC_E1_Current_Dis, TMC_E1_Current_buf_ch, 16, true);
+
+ const uint16_t Min_Ex_Temp_buf_ch[] = { 0xEED7, 0xA1D0, 0xB7BC, 0xF6B3, 0xC2CE, 0xC8B6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Min_Ex_Temp_Dis, Min_Ex_Temp_buf_ch, 32, true);
+
+ const uint16_t AutoLEVEL_INFO1_buf_ch[] = { 0xEBC7, 0xB4B0, 0xC2CF, 0xB4B0, 0xA5C5, 0x2000 };
+ dgusdisplay.WriteVariable(VP_AutoLEVEL_INFO1, AutoLEVEL_INFO1_buf_ch, 32, true);
+
+ const uint16_t EX_TEMP_INFO2_buf_ch[] = { 0xEBC7, 0xD4C9, 0xC8B5, 0x2000 };
+ dgusdisplay.WriteVariable(VP_EX_TEMP_INFO2_Dis, EX_TEMP_INFO2_buf_ch, 32, true);
+
+ const uint16_t EX_TEMP_INFO3_buf_ch[] = { 0xA1C8, 0xFBCF, 0xD3BC, 0xC8C8, 0x2000 };
+ dgusdisplay.WriteVariable(VP_EX_TEMP_INFO3_Dis, EX_TEMP_INFO3_buf_ch, 32, true);
+
+ const uint16_t PrintConfrim_Info_buf_ch[] = { 0xC7CA, 0xF1B7, 0xAABF, 0xBCCA, 0xF2B4, 0xA1D3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_PrintConfrim_Info_Dis, PrintConfrim_Info_buf_ch, 32, true);
+
+ const uint16_t StopPrintConfrim_Info_buf_ch[] = { 0xC7CA, 0xF1B7, 0xA3CD, 0xB9D6, 0xF2B4, 0xA1D3, 0x2000 };
+ dgusdisplay.WriteVariable(VP_StopPrintConfrim_Info_Dis, StopPrintConfrim_Info_buf_ch, 32, true);
+
+ const uint16_t Printting_buf_ch[] = { 0xF2B4, 0xA1D3, 0xD0D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_Printting_Dis, Printting_buf_ch, 32, true);
+
+ const uint16_t LCD_BLK_buf_ch[] = { 0xB3B1, 0xE2B9, 0xE8C9, 0xC3D6, 0x2000 };
+ dgusdisplay.WriteVariable(VP_LCD_BLK_Dis, LCD_BLK_buf_ch, 32, true);
+ }
+}
+
+#endif // DGUS_LCD_UI_MKS
diff --git a/src/lcd/extui/dgus/mks/DGUSScreenHandler.h b/src/lcd/extui/dgus/mks/DGUSScreenHandler.h
new file mode 100644
index 0000000..823ed42
--- /dev/null
+++ b/src/lcd/extui/dgus/mks/DGUSScreenHandler.h
@@ -0,0 +1,116 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+#include "../DGUSScreenHandlerBase.h"
+
+enum DGUSLCD_Screens : uint8_t;
+
+class DGUSScreenHandlerMKS : public DGUSScreenHandler {
+public:
+ DGUSScreenHandlerMKS() = default;
+
+ #if 0
+ static void sendinfoscreen_ch(const uint16_t *line1, const uint16_t *line2, const uint16_t *line3, const uint16_t *line4);
+ static void sendinfoscreen_en(PGM_P const line1, PGM_P const line2, PGM_P const line3, PGM_P const line4);
+ static void sendinfoscreen(const void *line1, const void *line2, const void *line3, const void *line4, uint16_t language);
+ #endif
+
+ static void ScreenBackChange(DGUS_VP_Variable &var, void *val_ptr);
+
+ static void EEPROM_CTRL(DGUS_VP_Variable &var, void *val_ptr);
+ static void LanguageChange(DGUS_VP_Variable &var, void *val_ptr);
+ static void GetOffsetValue(DGUS_VP_Variable &var, void *val_ptr);
+ static void Level_Ctrl(DGUS_VP_Variable &var, void *val_ptr);
+ static void MeshLevel(DGUS_VP_Variable &var, void *val_ptr);
+ static void MeshLevelDistanceConfig(DGUS_VP_Variable &var, void *val_ptr);
+ static void ManualAssistLeveling(DGUS_VP_Variable &var, void *val_ptr);
+ static void ZoffsetConfirm(DGUS_VP_Variable &var, void *val_ptr);
+ static void Z_offset_select(DGUS_VP_Variable &var, void *val_ptr);
+ static void GetManualMovestep(DGUS_VP_Variable &var, void *val_ptr);
+ static void GetZoffsetDistance(DGUS_VP_Variable &var, void *val_ptr);
+ static void GetMinExtrudeTemp(DGUS_VP_Variable &var, void *val_ptr);
+ static void GetParkPos(DGUS_VP_Variable &var, void *val_ptr);
+ #if ENABLED(PREVENT_COLD_EXTRUSION)
+ static void HandleGetExMinTemp(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+ static void DGUS_LanguageDisplay(uint8_t var);
+ static void TMC_ChangeConfig(DGUS_VP_Variable &var, void *val_ptr);
+ static void GetTurnOffCtrl(DGUS_VP_Variable &var, void *val_ptr);
+ static void LanguagePInit();
+ static void DGUS_Runout_Idle();
+ static void DGUS_RunoutInit();
+ static void DGUS_ExtrudeLoadInit();
+ static void LCD_BLK_Adjust(DGUS_VP_Variable &var, void *val_ptr);
+ static void SD_FileBack(DGUS_VP_Variable &var, void *val_ptr);
+
+ static void HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleStepPerMMExtruderChanged(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleMaxSpeedChange(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleExtruderMaxSpeedChange(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleAccChange(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleMaxAccChange(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleExtruderAccChange(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleChangeLevelPoint(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleTravelAccChange(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleFeedRateMinChange(DGUS_VP_Variable &var, void *val_ptr);
+ static void HandleMin_T_F(DGUS_VP_Variable &var, void *val_ptr);
+
+ #if HAS_PID_HEATING
+ static void FilamentLoadUnload(DGUS_VP_Variable &var, void *val_ptr, const int filamentDir);
+ static void FilamentLoad(DGUS_VP_Variable &var, void *val_ptr);
+ static void FilamentUnLoad(DGUS_VP_Variable &var, void *val_ptr);
+ static void GetManualFilament(DGUS_VP_Variable &var, void *val_ptr);
+ static void GetManualFilamentSpeed(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+
+ #if ENABLED(SDSUPPORT)
+ // Marlin informed us about SD print completion.
+ static void SDPrintingFinished();
+ #else
+ static void PrintReturn(DGUS_VP_Variable &var, void *val_ptr);
+ #endif
+
+ static void DGUSLCD_SendPrintTimeToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendBabyStepToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendFanToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendGbkToDisplay(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendStringToDisplay_Language(DGUS_VP_Variable &var);
+ static void DGUSLCD_SendTMCStepValue(DGUS_VP_Variable &var);
+
+ static void DGUSLCD_SetUint8(DGUS_VP_Variable &var, void *val_ptr);
+
+ static bool loop();
+};
+
+enum MKS_Choose : uint8_t { MKS_Language_Choose, MKS_Language_NoChoose };
+enum MKS_Language : uint8_t { MKS_SimpleChinese, MKS_English };
+
+extern MKS_Language mks_language_index;
+extern bool DGUSAutoTurnOff;
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #define PLR_SCREEN_RECOVER MKSLCD_SCREEN_PRINT
+ #define PLR_SCREEN_CANCEL MKSLCD_SCREEN_HOME
+#endif
+
+typedef DGUSScreenHandlerMKS DGUSScreenHandlerClass;
diff --git a/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp b/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp
new file mode 100644
index 0000000..0115d3b
--- /dev/null
+++ b/src/lcd/extui/dgus/origin/DGUSDisplayDef.cpp
@@ -0,0 +1,279 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/**
+ * lcd/extui/dgus/origin/DGUSDisplayDef.cpp
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_ORIGIN)
+
+#include "DGUSDisplayDef.h"
+#include "../DGUSDisplay.h"
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+
+#include "../../../marlinui.h"
+#include "../../ui_api.h"
+
+#if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ uint16_t distanceToMove = 10;
+#endif
+using namespace ExtUI;
+
+const uint16_t VPList_Boot[] PROGMEM = {
+ VP_MARLIN_VERSION,
+ 0x0000
+};
+
+const uint16_t VPList_Main[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded.
+ 0x0000
+};
+
+const uint16_t VPList_Temp[] PROGMEM = {
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ 0x0000
+};
+
+const uint16_t VPList_Status[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded
+ #if HAS_HOTEND
+ VP_T_E0_Is, VP_T_E0_Set,
+ #if HAS_MULTI_HOTEND
+ VP_T_E1_Is, VP_T_E1_Set,
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VP_T_Bed_Is, VP_T_Bed_Set,
+ #endif
+ #if HAS_FAN
+ VP_Fan0_Percentage,
+ #endif
+ VP_XPos, VP_YPos, VP_ZPos,
+ VP_Fan0_Percentage,
+ VP_Feedrate_Percentage,
+ VP_PrintProgress_Percentage,
+ 0x0000
+};
+
+const uint16_t VPList_Status2[] PROGMEM = {
+ // VP_M117, for completeness, but it cannot be auto-uploaded
+ #if HAS_HOTEND
+ VP_Flowrate_E0,
+ #if HAS_MULTI_HOTEND
+ VP_Flowrate_E1,
+ #endif
+ #endif
+ VP_PrintProgress_Percentage,
+ VP_PrintTime,
+ 0x0000
+};
+const uint16_t VPList_ManualMove[] PROGMEM = { VP_XPos, VP_YPos, VP_ZPos, 0x0000 };
+const uint16_t VPList_ManualExtrude[] PROGMEM = { VP_EPos, 0x0000 };
+const uint16_t VPList_FanAndFeedrate[] PROGMEM = { VP_Feedrate_Percentage, VP_Fan0_Percentage, 0x0000 };
+const uint16_t VPList_SD_FlowRates[] PROGMEM = { VP_Flowrate_E0, VP_Flowrate_E1, 0x0000 };
+const uint16_t VPList_SDFileList[] PROGMEM = { VP_SD_FileName0, VP_SD_FileName1, VP_SD_FileName2, VP_SD_FileName3, VP_SD_FileName4, 0x0000 };
+const uint16_t VPList_SD_PrintManipulation[] PROGMEM = { VP_PrintProgress_Percentage, VP_PrintTime, 0x0000 };
+
+const struct VPMapping VPMap[] PROGMEM = {
+ { DGUSLCD_SCREEN_BOOT, VPList_Boot },
+ { DGUSLCD_SCREEN_MAIN, VPList_Main },
+ { DGUSLCD_SCREEN_TEMPERATURE, VPList_Temp },
+ { DGUSLCD_SCREEN_STATUS, VPList_Status },
+ { DGUSLCD_SCREEN_STATUS2, VPList_Status2 },
+ { DGUSLCD_SCREEN_MANUALMOVE, VPList_ManualMove },
+ { DGUSLCD_SCREEN_MANUALEXTRUDE, VPList_ManualExtrude },
+ { DGUSLCD_SCREEN_FANANDFEEDRATE, VPList_FanAndFeedrate },
+ { DGUSLCD_SCREEN_FLOWRATES, VPList_SD_FlowRates },
+ { DGUSLCD_SCREEN_SDPRINTMANIPULATION, VPList_SD_PrintManipulation },
+ { DGUSLCD_SCREEN_SDFILELIST, VPList_SDFileList },
+ { 0 , nullptr } // List is terminated with an nullptr as table entry.
+};
+
+const char MarlinVersion[] PROGMEM = SHORT_BUILD_VERSION;
+
+const struct DGUS_VP_Variable ListOfVP[] PROGMEM = {
+ // Helper to detect touch events
+ VPHELPER(VP_SCREENCHANGE, nullptr, ScreenHandler.ScreenChangeHook, nullptr),
+ VPHELPER(VP_SCREENCHANGE_ASK, nullptr, ScreenHandler.ScreenChangeHookIfIdle, nullptr),
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SCREENCHANGE_WHENSD, nullptr, ScreenHandler.ScreenChangeHookIfSD, nullptr),
+ #endif
+ VPHELPER(VP_CONFIRMED, nullptr, ScreenHandler.ScreenConfirmedOK, nullptr),
+
+ VPHELPER(VP_TEMP_ALL_OFF, nullptr, ScreenHandler.HandleAllHeatersOff, nullptr),
+
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_OPTION, &distanceToMove, ScreenHandler.HandleManualMoveOption, nullptr),
+ #endif
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ VPHELPER(VP_MOVE_X, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, &distanceToMove, ScreenHandler.HandleManualMove, nullptr),
+ #else
+ VPHELPER(VP_MOVE_X, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Y, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_MOVE_Z, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ VPHELPER(VP_HOME_ALL, nullptr, ScreenHandler.HandleManualMove, nullptr),
+ #endif
+
+ VPHELPER(VP_MOTOR_LOCK_UNLOK, nullptr, ScreenHandler.HandleMotorLockUnlock, nullptr),
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ VPHELPER(VP_POWER_LOSS_RECOVERY, nullptr, ScreenHandler.HandlePowerLossRecovery, nullptr),
+ #endif
+ VPHELPER(VP_SETTINGS, nullptr, ScreenHandler.HandleSettings, nullptr),
+
+ { .VP = VP_MARLIN_VERSION, .memadr = (void*)MarlinVersion, .size = VP_MARLIN_VERSION_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ // M117 LCD String (We don't need the string in memory but "just" push it to the display on demand, hence the nullptr
+ { .VP = VP_M117, .memadr = nullptr, .size = VP_M117_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplay },
+
+ // Temperature Data
+ #if HAS_HOTEND
+ VPHELPER(VP_T_E0_Is, &thermalManager.temp_hotend[0].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E0_Set, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleTemperatureChanged, &ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E0, nullptr, ScreenHandler.HandleFlowRateChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_EPos, &destination.e, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_MOVE_E0, nullptr, ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E0_CONTROL, &thermalManager.temp_hotend[0].target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E0_STATUS, &thermalManager.temp_hotend[0].target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(DGUS_PREHEAT_UI)
+ VPHELPER(VP_E0_BED_PREHEAT, nullptr, ScreenHandler.HandlePreheat, nullptr),
+ #endif
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_E0_PID_P, &thermalManager.temp_hotend[0].pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_I, &thermalManager.temp_hotend[0].pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_E0_PID_D, &thermalManager.temp_hotend[0].pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_PID_AUTOTUNE_E0, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+ VPHELPER(VP_E0_FILAMENT_LOAD_UNLOAD, nullptr, ScreenHandler.HandleFilamentOption, ScreenHandler.HandleFilamentLoadUnload),
+ #endif
+ #endif
+ #if HAS_MULTI_HOTEND
+ VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_E1_Set, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_Flowrate_E1, nullptr, ScreenHandler.HandleFlowRateChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_MOVE_E1, nullptr, ScreenHandler.HandleManualExtrude, nullptr),
+ VPHELPER(VP_E1_CONTROL, &thermalManager.temp_hotend[1].target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_E1_STATUS, &thermalManager.temp_hotend[1].target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMP)
+ VPHELPER(VP_PID_AUTOTUNE_E1, nullptr, ScreenHandler.HandlePIDAutotune, nullptr),
+ #endif
+ #endif
+ #if HAS_HEATED_BED
+ VPHELPER(VP_T_Bed_Is, &thermalManager.temp_bed.celsius, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<0>),
+ VPHELPER(VP_T_Bed_Set, &thermalManager.temp_bed.target, ScreenHandler.HandleTemperatureChanged, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+ VPHELPER(VP_BED_CONTROL, &thermalManager.temp_bed.target, ScreenHandler.HandleHeaterControl, nullptr),
+ VPHELPER(VP_BED_STATUS, &thermalManager.temp_bed.target, nullptr, ScreenHandler.DGUSLCD_SendHeaterStatusToDisplay),
+ #if ENABLED(PIDTEMPBED)
+ VPHELPER(VP_BED_PID_P, &thermalManager.temp_bed.pid.Kp, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_I, &thermalManager.temp_bed.pid.Ki, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ VPHELPER(VP_BED_PID_D, &thermalManager.temp_bed.pid.Kd, ScreenHandler.HandleTemperaturePIDChanged, ScreenHandler.DGUSLCD_SendTemperaturePID),
+ #endif
+ #endif
+
+ // Fan Data
+ #if HAS_FAN
+ #define FAN_VPHELPER(N) \
+ VPHELPER(VP_Fan##N##_Percentage, &thermalManager.fan_speed[N], ScreenHandler.DGUSLCD_PercentageToUint8, ScreenHandler.DGUSLCD_SendPercentageToDisplay), \
+ VPHELPER(VP_FAN##N##_CONTROL, &thermalManager.fan_speed[N], ScreenHandler.HandleFanControl, nullptr), \
+ VPHELPER(VP_FAN##N##_STATUS, &thermalManager.fan_speed[N], nullptr, ScreenHandler.DGUSLCD_SendFanStatusToDisplay),
+ REPEAT(FAN_COUNT, FAN_VPHELPER)
+ #endif
+
+ // Feedrate
+ VPHELPER(VP_Feedrate_Percentage, &feedrate_percentage, ScreenHandler.DGUSLCD_SetValueDirectly, ScreenHandler.DGUSLCD_SendWordValueToDisplay),
+
+ // Position Data
+ VPHELPER(VP_XPos, ¤t_position.x, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_YPos, ¤t_position.y, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+ VPHELPER(VP_ZPos, ¤t_position.z, nullptr, ScreenHandler.DGUSLCD_SendFloatAsLongValueToDisplay<2>),
+
+ // Print Progress
+ VPHELPER(VP_PrintProgress_Percentage, nullptr, nullptr, ScreenHandler.DGUSLCD_SendPrintProgressToDisplay),
+
+ // Print Time
+ VPHELPER_STR(VP_PrintTime, nullptr, VP_PrintTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintTimeToDisplay),
+ #if ENABLED(PRINTCOUNTER)
+ VPHELPER_STR(VP_PrintAccTime, nullptr, VP_PrintAccTime_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintAccTimeToDisplay),
+ VPHELPER_STR(VP_PrintsTotal, nullptr, VP_PrintsTotal_LEN, nullptr, ScreenHandler.DGUSLCD_SendPrintsTotalToDisplay),
+ #endif
+
+ VPHELPER(VP_X_STEP_PER_MM, &planner.settings.axis_steps_per_mm[X_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Y_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Y_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ VPHELPER(VP_Z_STEP_PER_MM, &planner.settings.axis_steps_per_mm[Z_AXIS], ScreenHandler.HandleStepPerMMChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #if HAS_HOTEND
+ VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #if HAS_MULTI_HOTEND
+ VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>),
+ #endif
+ #endif
+
+ // SDCard File listing.
+ #if ENABLED(SDSUPPORT)
+ VPHELPER(VP_SD_ScrollEvent, nullptr, ScreenHandler.DGUSLCD_SD_ScrollFilelist, nullptr),
+ VPHELPER(VP_SD_FileSelected, nullptr, ScreenHandler.DGUSLCD_SD_FileSelected, nullptr),
+ VPHELPER(VP_SD_FileSelectConfirm, nullptr, ScreenHandler.DGUSLCD_SD_StartPrint, nullptr),
+ VPHELPER_STR(VP_SD_FileName0, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName1, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName2, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName3, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER_STR(VP_SD_FileName4, nullptr, VP_SD_FileName_LEN, nullptr, ScreenHandler.DGUSLCD_SD_SendFilename),
+ VPHELPER(VP_SD_ResumePauseAbort, nullptr, ScreenHandler.DGUSLCD_SD_ResumePauseAbort, nullptr),
+ VPHELPER(VP_SD_AbortPrintConfirmed, nullptr, ScreenHandler.DGUSLCD_SD_ReallyAbort, nullptr),
+ VPHELPER(VP_SD_Print_Setting, nullptr, ScreenHandler.DGUSLCD_SD_PrintTune, nullptr),
+ #if HAS_BED_PROBE
+ VPHELPER(VP_SD_Print_ProbeOffsetZ, &probe.offset.z, ScreenHandler.HandleProbeOffsetZChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<2>),
+ #if ENABLED(BABYSTEPPING)
+ VPHELPER(VP_SD_Print_LiveAdjustZ, nullptr, ScreenHandler.HandleLiveAdjustZ, nullptr),
+ #endif
+ #endif
+ #endif
+
+ #if ENABLED(DGUS_UI_WAITING)
+ VPHELPER(VP_WAITING_STATUS, nullptr, nullptr, ScreenHandler.DGUSLCD_SendWaitingStatusToDisplay),
+ #endif
+
+ // Messages for the User, shared by the popup and the kill screen. They can't be autouploaded as we do not buffer content.
+ { .VP = VP_MSGSTR1, .memadr = nullptr, .size = VP_MSGSTR1_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR2, .memadr = nullptr, .size = VP_MSGSTR2_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR3, .memadr = nullptr, .size = VP_MSGSTR3_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+ { .VP = VP_MSGSTR4, .memadr = nullptr, .size = VP_MSGSTR4_LEN, .set_by_display_handler = nullptr, .send_to_display_handler = ScreenHandler.DGUSLCD_SendStringToDisplayPGM },
+
+ VPHELPER(0, 0, 0, 0) // must be last entry.
+};
+
+#endif // DGUS_LCD_UI_ORIGIN
diff --git a/src/lcd/extui/dgus/origin/DGUSDisplayDef.h b/src/lcd/extui/dgus/origin/DGUSDisplayDef.h
new file mode 100644
index 0000000..f5fb986
--- /dev/null
+++ b/src/lcd/extui/dgus/origin/DGUSDisplayDef.h
@@ -0,0 +1,282 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+#include "../DGUSDisplayDef.h"
+
+enum DGUSLCD_Screens : uint8_t {
+ DGUSLCD_SCREEN_BOOT = 0,
+ DGUSLCD_SCREEN_MAIN = 10,
+ DGUSLCD_SCREEN_TEMPERATURE = 20,
+ DGUSLCD_SCREEN_STATUS = 30,
+ DGUSLCD_SCREEN_STATUS2 = 32,
+ DGUSLCD_SCREEN_MANUALMOVE = 40,
+ DGUSLCD_SCREEN_MANUALEXTRUDE = 42,
+ DGUSLCD_SCREEN_FANANDFEEDRATE = 44,
+ DGUSLCD_SCREEN_FLOWRATES = 46,
+ DGUSLCD_SCREEN_SDFILELIST = 50,
+ DGUSLCD_SCREEN_SDPRINTMANIPULATION = 52,
+ DGUSLCD_SCREEN_POWER_LOSS = 100,
+ DGUSLCD_SCREEN_PREHEAT = 120,
+ DGUSLCD_SCREEN_UTILITY = 110,
+ DGUSLCD_SCREEN_FILAMENT_HEATING = 146,
+ DGUSLCD_SCREEN_FILAMENT_LOADING = 148,
+ DGUSLCD_SCREEN_FILAMENT_UNLOADING = 158,
+ DGUSLCD_SCREEN_SDPRINTTUNE = 170,
+ DGUSLCD_SCREEN_CONFIRM = 240,
+ DGUSLCD_SCREEN_KILL = 250, ///< Kill Screen. Must always be 250 (to be able to display "Error wrong LCD Version")
+ DGUSLCD_SCREEN_WAITING = 251,
+ DGUSLCD_SCREEN_POPUP = 252, ///< special target, popup screen will also return this code to say "return to previous screen"
+ DGUSLCD_SCREEN_UNUSED = 255
+};
+
+// Display Memory layout used (T5UID)
+// Except system variables this is arbitrary, just to organize stuff....
+
+// 0x0000 .. 0x0FFF -- System variables and reserved by the display
+// 0x1000 .. 0x1FFF -- Variables to never change location, regardless of UI Version
+// 0x2000 .. 0x2FFF -- Controls (VPs that will trigger some action)
+// 0x3000 .. 0x4FFF -- Marlin Data to be displayed
+// 0x5000 .. -- SPs (if we want to modify display elements, e.g change color or like) -- currently unused
+
+// As there is plenty of space (at least most displays have >8k RAM), we do not pack them too tight,
+// so that we can keep variables nicely together in the address space.
+
+// UI Version always on 0x1000...0x1002 so that the firmware can check this and bail out.
+constexpr uint16_t VP_UI_VERSION_MAJOR = 0x1000; // Major -- incremented when incompatible
+constexpr uint16_t VP_UI_VERSION_MINOR = 0x1001; // Minor -- incremented on new features, but compatible
+constexpr uint16_t VP_UI_VERSION_PATCH = 0x1002; // Patch -- fixed which do not change functionality.
+constexpr uint16_t VP_UI_FLAVOUR = 0x1010; // lets reserve 16 bytes here to determine if UI is suitable for this Marlin. tbd.
+
+// Storage space for the Killscreen messages. 0x1100 - 0x1200 . Reused for the popup.
+constexpr uint16_t VP_MSGSTR1 = 0x1100;
+constexpr uint8_t VP_MSGSTR1_LEN = 0x20; // might be more place for it...
+constexpr uint16_t VP_MSGSTR2 = 0x1140;
+constexpr uint8_t VP_MSGSTR2_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR3 = 0x1180;
+constexpr uint8_t VP_MSGSTR3_LEN = 0x20;
+constexpr uint16_t VP_MSGSTR4 = 0x11C0;
+constexpr uint8_t VP_MSGSTR4_LEN = 0x20;
+
+// Screenchange request for screens that only make sense when printer is idle.
+// e.g movement is only allowed if printer is not printing.
+// Marlin must confirm by setting the screen manually.
+constexpr uint16_t VP_SCREENCHANGE_ASK = 0x2000;
+constexpr uint16_t VP_SCREENCHANGE = 0x2001; // Key-Return button to new menu pressed. Data contains target screen in low byte and info in high byte.
+constexpr uint16_t VP_TEMP_ALL_OFF = 0x2002; // Turn all heaters off. Value arbitrary ;)=
+constexpr uint16_t VP_SCREENCHANGE_WHENSD = 0x2003; // "Print" Button touched -- go only there if there is an SD Card.
+
+constexpr uint16_t VP_CONFIRMED = 0x2010; // OK on confirm screen.
+
+// Buttons on the SD-Card File listing.
+constexpr uint16_t VP_SD_ScrollEvent = 0x2020; // Data: 0 for "up a directory", numbers are the amount to scroll, e.g -1 one up, 1 one down
+constexpr uint16_t VP_SD_FileSelected = 0x2022; // Number of file field selected.
+constexpr uint16_t VP_SD_FileSelectConfirm = 0x2024; // (This is a virtual VP and emulated by the Confirm Screen when a file has been confirmed)
+
+constexpr uint16_t VP_SD_ResumePauseAbort = 0x2026; // Resume(Data=0), Pause(Data=1), Abort(Data=2) SD Card prints
+constexpr uint16_t VP_SD_AbortPrintConfirmed = 0x2028; // Abort print confirmation (virtual, will be injected by the confirm dialog)
+constexpr uint16_t VP_SD_Print_Setting = 0x2040;
+constexpr uint16_t VP_SD_Print_LiveAdjustZ = 0x2050; // Data: 0 down, 1 up
+
+// Controls for movement (we can't use the incremental / decremental feature of the display at this feature works only with 16 bit values
+// (which would limit us to 655.35mm, which is likely not a problem for common setups, but i don't want to rule out hangprinters support)
+// A word about the coding: The VP will be per axis and the return code will be an signed 16 bit value in 0.01 mm resolution, telling us
+// the relative travel amount t he user wants to do. So eg. if the display sends us VP=2100 with value 100, the user wants us to move X by +1 mm.
+constexpr uint16_t VP_MOVE_X = 0x2100;
+constexpr uint16_t VP_MOVE_Y = 0x2102;
+constexpr uint16_t VP_MOVE_Z = 0x2104;
+constexpr uint16_t VP_MOVE_E0 = 0x2110;
+constexpr uint16_t VP_MOVE_E1 = 0x2112;
+//constexpr uint16_t VP_MOVE_E2 = 0x2114;
+//constexpr uint16_t VP_MOVE_E3 = 0x2116;
+//constexpr uint16_t VP_MOVE_E4 = 0x2118;
+//constexpr uint16_t VP_MOVE_E5 = 0x211A;
+constexpr uint16_t VP_HOME_ALL = 0x2120;
+constexpr uint16_t VP_MOTOR_LOCK_UNLOK = 0x2130;
+
+// Power loss recovery
+constexpr uint16_t VP_POWER_LOSS_RECOVERY = 0x2180;
+
+// Fan Control Buttons , switch between "off" and "on"
+constexpr uint16_t VP_FAN0_CONTROL = 0x2200;
+constexpr uint16_t VP_FAN1_CONTROL = 0x2202;
+//constexpr uint16_t VP_FAN2_CONTROL = 0x2204;
+//constexpr uint16_t VP_FAN3_CONTROL = 0x2206;
+
+// Heater Control Buttons , triged between "cool down" and "heat PLA" state
+constexpr uint16_t VP_E0_CONTROL = 0x2210;
+constexpr uint16_t VP_E1_CONTROL = 0x2212;
+//constexpr uint16_t VP_E2_CONTROL = 0x2214;
+//constexpr uint16_t VP_E3_CONTROL = 0x2216;
+//constexpr uint16_t VP_E4_CONTROL = 0x2218;
+//constexpr uint16_t VP_E5_CONTROL = 0x221A;
+constexpr uint16_t VP_BED_CONTROL = 0x221C;
+
+// Preheat
+constexpr uint16_t VP_E0_BED_PREHEAT = 0x2220;
+constexpr uint16_t VP_E1_BED_CONTROL = 0x2222;
+//constexpr uint16_t VP_E2_BED_CONTROL = 0x2224;
+//constexpr uint16_t VP_E3_BED_CONTROL = 0x2226;
+//constexpr uint16_t VP_E4_BED_CONTROL = 0x2228;
+//constexpr uint16_t VP_E5_BED_CONTROL = 0x222A;
+
+// Filament load and unload
+constexpr uint16_t VP_E0_FILAMENT_LOAD_UNLOAD = 0x2300;
+constexpr uint16_t VP_E1_FILAMENT_LOAD_UNLOAD = 0x2302;
+
+// Settings store , reset
+constexpr uint16_t VP_SETTINGS = 0x2400;
+
+// PID autotune
+constexpr uint16_t VP_PID_AUTOTUNE_E0 = 0x2410;
+//constexpr uint16_t VP_PID_AUTOTUNE_E1 = 0x2412;
+//constexpr uint16_t VP_PID_AUTOTUNE_E2 = 0x2414;
+//constexpr uint16_t VP_PID_AUTOTUNE_E3 = 0x2416;
+//constexpr uint16_t VP_PID_AUTOTUNE_E4 = 0x2418;
+//constexpr uint16_t VP_PID_AUTOTUNE_E5 = 0x241A;
+constexpr uint16_t VP_PID_AUTOTUNE_BED = 0x2420;
+
+// Firmware version on the boot screen.
+constexpr uint16_t VP_MARLIN_VERSION = 0x3000;
+constexpr uint8_t VP_MARLIN_VERSION_LEN = 16; // there is more space on the display, if needed.
+
+// Place for status messages.
+constexpr uint16_t VP_M117 = 0x3020;
+constexpr uint8_t VP_M117_LEN = 0x20;
+
+// Temperatures.
+constexpr uint16_t VP_T_E0_Is = 0x3060; // 4 Byte Integer
+constexpr uint16_t VP_T_E0_Set = 0x3062; // 2 Byte Integer
+constexpr uint16_t VP_T_E1_Is = 0x3064; // 4 Byte Integer
+
+// reserved to support up to 6 Extruders:
+//constexpr uint16_t VP_T_E1_Set = 0x3066; // 2 Byte Integer
+//constexpr uint16_t VP_T_E2_Is = 0x3068; // 4 Byte Integer
+//constexpr uint16_t VP_T_E2_Set = 0x306A; // 2 Byte Integer
+//constexpr uint16_t VP_T_E3_Is = 0x306C; // 4 Byte Integer
+//constexpr uint16_t VP_T_E3_Set = 0x306E; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3070; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3072; // 2 Byte Integer
+//constexpr uint16_t VP_T_E4_Is = 0x3074; // 4 Byte Integer
+//constexpr uint16_t VP_T_E4_Set = 0x3076; // 2 Byte Integer
+//constexpr uint16_t VP_T_E5_Is = 0x3078; // 4 Byte Integer
+//constexpr uint16_t VP_T_E5_Set = 0x307A; // 2 Byte Integer
+
+constexpr uint16_t VP_T_Bed_Is = 0x3080; // 4 Byte Integer
+constexpr uint16_t VP_T_Bed_Set = 0x3082; // 2 Byte Integer
+
+constexpr uint16_t VP_Flowrate_E0 = 0x3090; // 2 Byte Integer
+constexpr uint16_t VP_Flowrate_E1 = 0x3092; // 2 Byte Integer
+
+// reserved for up to 6 Extruders:
+//constexpr uint16_t VP_Flowrate_E2 = 0x3094;
+//constexpr uint16_t VP_Flowrate_E3 = 0x3096;
+//constexpr uint16_t VP_Flowrate_E4 = 0x3098;
+//constexpr uint16_t VP_Flowrate_E5 = 0x309A;
+
+constexpr uint16_t VP_Fan0_Percentage = 0x3100; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_Fan1_Percentage = 0x33A2; // 2 Byte Integer (0..100)
+//constexpr uint16_t VP_Fan2_Percentage = 0x33A4; // 2 Byte Integer (0..100)
+//constexpr uint16_t VP_Fan3_Percentage = 0x33A6; // 2 Byte Integer (0..100)
+
+constexpr uint16_t VP_Feedrate_Percentage = 0x3102; // 2 Byte Integer (0..100)
+constexpr uint16_t VP_PrintProgress_Percentage = 0x3104; // 2 Byte Integer (0..100)
+
+constexpr uint16_t VP_PrintTime = 0x3106;
+constexpr uint16_t VP_PrintTime_LEN = 10;
+
+constexpr uint16_t VP_PrintAccTime = 0x3160;
+constexpr uint16_t VP_PrintAccTime_LEN = 32;
+
+constexpr uint16_t VP_PrintsTotal = 0x3180;
+constexpr uint16_t VP_PrintsTotal_LEN = 16;
+
+// Actual Position
+constexpr uint16_t VP_XPos = 0x3110; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_YPos = 0x3112; // 4 Byte Fixed point number; format xxx.yy
+constexpr uint16_t VP_ZPos = 0x3114; // 4 Byte Fixed point number; format xxx.yy
+
+constexpr uint16_t VP_EPos = 0x3120; // 4 Byte Fixed point number; format xxx.yy
+
+// SDCard File Listing
+constexpr uint16_t VP_SD_FileName_LEN = 32; // LEN is shared for all entries.
+constexpr uint16_t DGUS_SD_FILESPERSCREEN = 5; // FIXME move that info to the display and read it from there.
+constexpr uint16_t VP_SD_FileName0 = 0x3200;
+constexpr uint16_t VP_SD_FileName1 = 0x3220;
+constexpr uint16_t VP_SD_FileName2 = 0x3240;
+constexpr uint16_t VP_SD_FileName3 = 0x3260;
+constexpr uint16_t VP_SD_FileName4 = 0x3280;
+
+constexpr uint16_t VP_SD_Print_ProbeOffsetZ = 0x32A0; //
+constexpr uint16_t VP_SD_Print_Filename = 0x32C0; //
+
+// Fan status
+constexpr uint16_t VP_FAN0_STATUS = 0x3300;
+constexpr uint16_t VP_FAN1_STATUS = 0x3302;
+//constexpr uint16_t VP_FAN2_STATUS = 0x3304;
+//constexpr uint16_t VP_FAN3_STATUS = 0x3306;
+
+// Heater status
+constexpr uint16_t VP_E0_STATUS = 0x3310;
+//constexpr uint16_t VP_E1_STATUS = 0x3312;
+//constexpr uint16_t VP_E2_STATUS = 0x3314;
+//constexpr uint16_t VP_E3_STATUS = 0x3316;
+//constexpr uint16_t VP_E4_STATUS = 0x3318;
+//constexpr uint16_t VP_E5_STATUS = 0x331A;
+constexpr uint16_t VP_BED_STATUS = 0x331C;
+
+constexpr uint16_t VP_MOVE_OPTION = 0x3400;
+
+// Step per mm
+constexpr uint16_t VP_X_STEP_PER_MM = 0x3600; // at the moment , 2 byte unsigned int , 0~1638.4
+//constexpr uint16_t VP_X2_STEP_PER_MM = 0x3602;
+constexpr uint16_t VP_Y_STEP_PER_MM = 0x3604;
+//constexpr uint16_t VP_Y2_STEP_PER_MM = 0x3606;
+constexpr uint16_t VP_Z_STEP_PER_MM = 0x3608;
+//constexpr uint16_t VP_Z2_STEP_PER_MM = 0x360A;
+constexpr uint16_t VP_E0_STEP_PER_MM = 0x3610;
+//constexpr uint16_t VP_E1_STEP_PER_MM = 0x3612;
+//constexpr uint16_t VP_E2_STEP_PER_MM = 0x3614;
+//constexpr uint16_t VP_E3_STEP_PER_MM = 0x3616;
+//constexpr uint16_t VP_E4_STEP_PER_MM = 0x3618;
+//constexpr uint16_t VP_E5_STEP_PER_MM = 0x361A;
+
+// PIDs
+constexpr uint16_t VP_E0_PID_P = 0x3700; // at the moment , 2 byte unsigned int , 0~1638.4
+constexpr uint16_t VP_E0_PID_I = 0x3702;
+constexpr uint16_t VP_E0_PID_D = 0x3704;
+constexpr uint16_t VP_BED_PID_P = 0x3710;
+constexpr uint16_t VP_BED_PID_I = 0x3712;
+constexpr uint16_t VP_BED_PID_D = 0x3714;
+
+// Waiting screen status
+constexpr uint16_t VP_WAITING_STATUS = 0x3800;
+
+// SPs for certain variables...
+// located at 0x5000 and up
+// Not used yet!
+// This can be used e.g to make controls / data display invisible
+constexpr uint16_t SP_T_E0_Is = 0x5000;
+constexpr uint16_t SP_T_E0_Set = 0x5010;
+constexpr uint16_t SP_T_E1_Is = 0x5020;
+constexpr uint16_t SP_T_Bed_Is = 0x5030;
+constexpr uint16_t SP_T_Bed_Set = 0x5040;
diff --git a/src/lcd/extui/dgus/origin/DGUSScreenHandler.cpp b/src/lcd/extui/dgus/origin/DGUSScreenHandler.cpp
new file mode 100644
index 0000000..aaa8b72
--- /dev/null
+++ b/src/lcd/extui/dgus/origin/DGUSScreenHandler.cpp
@@ -0,0 +1,423 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_ORIGIN)
+
+#include "../DGUSScreenHandler.h"
+
+#include "../../../../MarlinCore.h"
+#include "../../../../gcode/queue.h"
+#include "../../../../libs/duration_t.h"
+#include "../../../../module/settings.h"
+#include "../../../../module/temperature.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/planner.h"
+#include "../../../../module/printcounter.h"
+#include "../../../../sd/cardreader.h"
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../../feature/powerloss.h"
+#endif
+
+#if ENABLED(SDSUPPORT)
+
+ extern ExtUI::FileList filelist;
+
+ void DGUSScreenHandler::DGUSLCD_SD_FileSelected(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t touched_nr = (int16_t)swap16(*(uint16_t*)val_ptr) + top_file;
+ if (touched_nr > filelist.count()) return;
+ if (!filelist.seek(touched_nr)) return;
+
+ if (filelist.isDir()) {
+ filelist.changeDir(filelist.filename());
+ top_file = 0;
+ ForceCompleteUpdate();
+ return;
+ }
+
+ #if ENABLED(DGUS_PRINT_FILENAME)
+ // Send print filename
+ dgusdisplay.WriteVariable(VP_SD_Print_Filename, filelist.filename(), VP_SD_FileName_LEN, true);
+ #endif
+
+ // Setup Confirmation screen
+ file_to_print = touched_nr;
+
+ HandleUserConfirmationPopUp(VP_SD_FileSelectConfirm, nullptr, PSTR("Print file"), filelist.filename(), PSTR("from SD Card?"), true, true, false, true);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_StartPrint(DGUS_VP_Variable &var, void *val_ptr) {
+ if (!filelist.seek(file_to_print)) return;
+ ExtUI::printFile(filelist.shortFilename());
+ GotoScreen(DGUSLCD_SCREEN_STATUS);
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_ResumePauseAbort(DGUS_VP_Variable &var, void *val_ptr) {
+
+ if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
+ switch (swap16(*(uint16_t*)val_ptr)) {
+ case 0: { // Resume
+ if (ExtUI::isPrintingFromMediaPaused()) {
+ ExtUI::resumePrint();
+ }
+ } break;
+
+ case 1: // Pause
+
+ GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION);
+ if (!ExtUI::isPrintingFromMediaPaused()) {
+ ExtUI::pausePrint();
+ //ExtUI::mks_pausePrint();
+ }
+ break;
+ case 2: // Abort
+ HandleUserConfirmationPopUp(VP_SD_AbortPrintConfirmed, nullptr, PSTR("Abort printing"), filelist.filename(), PSTR("?"), true, true, false, true);
+ break;
+ }
+ }
+
+ void DGUSScreenHandler::DGUSLCD_SD_SendFilename(DGUS_VP_Variable& var) {
+ uint16_t target_line = (var.VP - VP_SD_FileName0) / VP_SD_FileName_LEN;
+ if (target_line > DGUS_SD_FILESPERSCREEN) return;
+ char tmpfilename[VP_SD_FileName_LEN + 1] = "";
+ var.memadr = (void*)tmpfilename;
+
+ if (filelist.seek(top_file + target_line)) {
+ snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s%c"), filelist.filename(), filelist.isDir() ? '/' : 0); // snprintf_P(tmpfilename, VP_SD_FileName_LEN, PSTR("%s"), filelist.filename());
+ }
+ DGUSLCD_SendStringToDisplay(var);
+ }
+
+ void DGUSScreenHandler::SDCardInserted() {
+ top_file = 0;
+ filelist.refresh();
+ auto cs = getCurrentScreen();
+ if (cs == DGUSLCD_SCREEN_MAIN || cs == DGUSLCD_SCREEN_STATUS)
+ GotoScreen(DGUSLCD_SCREEN_SDFILELIST);
+ }
+
+ void DGUSScreenHandler::SDCardRemoved() {
+ if (current_screen == DGUSLCD_SCREEN_SDFILELIST
+ || (current_screen == DGUSLCD_SCREEN_CONFIRM && (ConfirmVP == VP_SD_AbortPrintConfirmed || ConfirmVP == VP_SD_FileSelectConfirm))
+ || current_screen == DGUSLCD_SCREEN_SDPRINTMANIPULATION
+ ) GotoScreen(DGUSLCD_SCREEN_MAIN);
+ }
+
+#endif // SDSUPPORT
+
+void DGUSScreenHandler::ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr) {
+ uint8_t *tmp = (uint8_t*)val_ptr;
+
+ // The keycode in target is coded as , so 0x0100A means
+ // from screen 1 (main) to 10 (temperature). DGUSLCD_SCREEN_POPUP is special,
+ // meaning "return to previous screen"
+ DGUSLCD_Screens target = (DGUSLCD_Screens)tmp[1];
+
+ DEBUG_ECHOLNPGM("\n DEBUG target", target);
+
+ if (target == DGUSLCD_SCREEN_POPUP) {
+ // Special handling for popup is to return to previous menu
+ if (current_screen == DGUSLCD_SCREEN_POPUP && confirm_action_cb) confirm_action_cb();
+ PopToOldScreen();
+ return;
+ }
+
+ UpdateNewScreen(target);
+
+ #ifdef DEBUG_DGUSLCD
+ if (!DGUSLCD_FindScreenVPMapList(target)) DEBUG_ECHOLNPGM("WARNING: No screen Mapping found for ", target);
+ #endif
+}
+
+void DGUSScreenHandler::HandleManualMove(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleManualMove");
+
+ int16_t movevalue = swap16(*(uint16_t*)val_ptr);
+ #if ENABLED(DGUS_UI_MOVE_DIS_OPTION)
+ if (movevalue) {
+ const uint16_t choice = *(uint16_t*)var.memadr;
+ movevalue = movevalue < 0 ? -choice : choice;
+ }
+ #endif
+ char axiscode;
+ unsigned int speed = 1500; // FIXME: get default feedrate for manual moves, don't hardcode.
+
+ switch (var.VP) {
+ default: return;
+
+ case VP_MOVE_X:
+ axiscode = 'X';
+ if (!ExtUI::canMove(ExtUI::axis_t::X)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Y:
+ axiscode = 'Y';
+ if (!ExtUI::canMove(ExtUI::axis_t::Y)) goto cannotmove;
+ break;
+
+ case VP_MOVE_Z:
+ axiscode = 'Z';
+ speed = 300; // default to 5mm/s
+ if (!ExtUI::canMove(ExtUI::axis_t::Z)) goto cannotmove;
+ break;
+
+ case VP_HOME_ALL: // only used for homing
+ axiscode = '\0';
+ movevalue = 0; // ignore value sent from display, this VP is _ONLY_ for homing.
+ break;
+ }
+
+ if (!movevalue) {
+ // homing
+ DEBUG_ECHOPGM(" homing ", AS_CHAR(axiscode));
+ char buf[6] = "G28 X";
+ buf[4] = axiscode;
+ //DEBUG_ECHOPGM(" ", buf);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOLNPGM(" ✓");
+ ForceCompleteUpdate();
+ return;
+ }
+ else {
+ // movement
+ DEBUG_ECHOPGM(" move ", AS_CHAR(axiscode));
+ bool old_relative_mode = relative_mode;
+ if (!relative_mode) {
+ //DEBUG_ECHOPGM(" G91");
+ queue.enqueue_now(F("G91"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ char buf[32]; // G1 X9999.99 F12345
+ unsigned int backup_speed = MMS_TO_MMM(feedrate_mm_s);
+ char sign[] = "\0";
+ int16_t value = movevalue / 100;
+ if (movevalue < 0) { value = -value; sign[0] = '-'; }
+ int16_t fraction = ABS(movevalue) % 100;
+ snprintf_P(buf, 32, PSTR("G0 %c%s%d.%02d F%d"), axiscode, sign, value, fraction, speed);
+ //DEBUG_ECHOPGM(" ", buf);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOLNPGM(" ✓ ");
+ if (backup_speed != speed) {
+ snprintf_P(buf, 32, PSTR("G0 F%d"), backup_speed);
+ queue.enqueue_one_now(buf);
+ //DEBUG_ECHOPGM(" ", buf);
+ }
+ // while (!enqueue_and_echo_command(buf)) idle();
+ //DEBUG_ECHOLNPGM(" ✓ ");
+ if (!old_relative_mode) {
+ //DEBUG_ECHOPGM("G90");
+ queue.enqueue_now(F("G90"));
+ //DEBUG_ECHOPGM(" ✓ ");
+ }
+ }
+
+ ForceCompleteUpdate();
+ DEBUG_ECHOLNPGM("manmv done.");
+ return;
+
+ cannotmove:
+ DEBUG_ECHOLNPGM(" cannot move ", AS_CHAR(axiscode));
+ return;
+}
+
+#if HAS_PID_HEATING
+ void DGUSScreenHandler::HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr) {
+ uint16_t rawvalue = swap16(*(uint16_t*)val_ptr);
+ DEBUG_ECHOLNPGM("V1:", rawvalue);
+ float value = (float)rawvalue / 10;
+ DEBUG_ECHOLNPGM("V2:", value);
+ float newvalue = 0;
+
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_PID_P: newvalue = value; break;
+ case VP_E0_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E0_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_PID_P: newvalue = value; break;
+ case VP_E1_PID_I: newvalue = scalePID_i(value); break;
+ case VP_E1_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ #if HAS_HEATED_BED
+ case VP_BED_PID_P: newvalue = value; break;
+ case VP_BED_PID_I: newvalue = scalePID_i(value); break;
+ case VP_BED_PID_D: newvalue = scalePID_d(value); break;
+ #endif
+ }
+
+ DEBUG_ECHOLNPGM("V3:", newvalue);
+ *(float *)var.memadr = newvalue;
+
+ skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel
+ }
+#endif // HAS_PID_HEATING
+
+#if ENABLED(BABYSTEPPING)
+ void DGUSScreenHandler::HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleLiveAdjustZ");
+ int16_t flag = swap16(*(uint16_t*)val_ptr),
+ steps = flag ? -20 : 20;
+ ExtUI::smartAdjustAxis_steps(steps, ExtUI::axis_t::Z, true);
+ ForceCompleteUpdate();
+ }
+#endif
+
+#if ENABLED(DGUS_FILAMENT_LOADUNLOAD)
+
+ void DGUSScreenHandler::HandleFilamentOption(DGUS_VP_Variable &var, void *val_ptr) {
+ DEBUG_ECHOLNPGM("HandleFilamentOption");
+
+ uint8_t e_temp = 0;
+ filament_data.heated = false;
+ uint16_t preheat_option = swap16(*(uint16_t*)val_ptr);
+ if (preheat_option <= 8) { // Load filament type
+ filament_data.action = 1;
+ }
+ else if (preheat_option >= 10) { // Unload filament type
+ preheat_option -= 10;
+ filament_data.action = 2;
+ filament_data.purge_length = DGUS_FILAMENT_PURGE_LENGTH;
+ }
+ else { // Cancel filament operation
+ filament_data.action = 0;
+ }
+
+ switch (preheat_option) {
+ case 0: // Load PLA
+ #ifdef PREHEAT_1_TEMP_HOTEND
+ e_temp = PREHEAT_1_TEMP_HOTEND;
+ #endif
+ break;
+ case 1: // Load ABS
+ TERN_(PREHEAT_2_TEMP_HOTEND, e_temp = PREHEAT_2_TEMP_HOTEND);
+ break;
+ case 2: // Load PET
+ #ifdef PREHEAT_3_TEMP_HOTEND
+ e_temp = PREHEAT_3_TEMP_HOTEND;
+ #endif
+ break;
+ case 3: // Load FLEX
+ #ifdef PREHEAT_4_TEMP_HOTEND
+ e_temp = PREHEAT_4_TEMP_HOTEND;
+ #endif
+ break;
+ case 9: // Cool down
+ default:
+ e_temp = 0;
+ break;
+ }
+
+ if (filament_data.action == 0) { // Go back to utility screen
+ #if HAS_HOTEND
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0);
+ #if HAS_MULTI_HOTEND
+ thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E1);
+ #endif
+ #endif
+ GotoScreen(DGUSLCD_SCREEN_UTILITY);
+ }
+ else { // Go to the preheat screen to show the heating progress
+ switch (var.VP) {
+ default: return;
+ #if HAS_HOTEND
+ case VP_E0_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E0;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case VP_E1_FILAMENT_LOAD_UNLOAD:
+ filament_data.extruder = ExtUI::extruder_t::E1;
+ thermalManager.setTargetHotend(e_temp, filament_data.extruder);
+ break;
+ #endif
+ }
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_HEATING);
+ }
+ }
+
+ void DGUSScreenHandler::HandleFilamentLoadUnload(DGUS_VP_Variable &var) {
+ DEBUG_ECHOLNPGM("HandleFilamentLoadUnload");
+ if (filament_data.action <= 0) return;
+
+ // If we close to the target temperature, we can start load or unload the filament
+ if (thermalManager.hotEnoughToExtrude(filament_data.extruder) && \
+ thermalManager.targetHotEnoughToExtrude(filament_data.extruder)) {
+ float movevalue = DGUS_FILAMENT_LOAD_LENGTH_PER_TIME;
+
+ if (filament_data.action == 1) { // load filament
+ if (!filament_data.heated) {
+ //GotoScreen(DGUSLCD_SCREEN_FILAMENT_LOADING);
+ filament_data.heated = true;
+ }
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
+ }
+ else { // unload filament
+ if (!filament_data.heated) {
+ GotoScreen(DGUSLCD_SCREEN_FILAMENT_UNLOADING);
+ filament_data.heated = true;
+ }
+ // Before unloading extrude to prevent jamming
+ if (filament_data.purge_length >= 0) {
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) + movevalue;
+ filament_data.purge_length -= movevalue;
+ }
+ else {
+ movevalue = ExtUI::getAxisPosition_mm(filament_data.extruder) - movevalue;
+ }
+ }
+ ExtUI::setAxisPosition_mm(movevalue, filament_data.extruder);
+ }
+ }
+#endif // DGUS_FILAMENT_LOADUNLOAD
+
+bool DGUSScreenHandler::loop() {
+ dgusdisplay.loop();
+
+ const millis_t ms = millis();
+ static millis_t next_event_ms = 0;
+
+ if (!IsScreenComplete() || ELAPSED(ms, next_event_ms)) {
+ next_event_ms = ms + DGUS_UPDATE_INTERVAL_MS;
+ UpdateScreenVPData();
+ }
+
+ #if ENABLED(SHOW_BOOTSCREEN)
+ static bool booted = false;
+
+ if (!booted && TERN0(POWER_LOSS_RECOVERY, recovery.valid()))
+ booted = true;
+
+ if (!booted && ELAPSED(ms, BOOTSCREEN_TIMEOUT)) {
+ booted = true;
+ GotoScreen(TERN0(POWER_LOSS_RECOVERY, recovery.valid()) ? DGUSLCD_SCREEN_POWER_LOSS : DGUSLCD_SCREEN_MAIN);
+ }
+ #endif
+
+ return IsScreenComplete();
+}
+
+#endif // DGUS_LCD_UI_ORIGIN
diff --git a/src/lcd/extui/dgus/origin/DGUSScreenHandler.h b/src/lcd/extui/dgus/origin/DGUSScreenHandler.h
new file mode 100644
index 0000000..73e3527
--- /dev/null
+++ b/src/lcd/extui/dgus/origin/DGUSScreenHandler.h
@@ -0,0 +1,31 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+#pragma once
+
+#include "../DGUSScreenHandlerBase.h"
+
+typedef DGUSScreenHandler DGUSScreenHandlerClass;
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #define PLR_SCREEN_RECOVER DGUSLCD_SCREEN_SDPRINTMANIPULATION
+ #define PLR_SCREEN_CANCEL DGUSLCD_SCREEN_STATUS
+#endif
diff --git a/src/lcd/extui/dgus_reloaded/DGUSDisplay.cpp b/src/lcd/extui/dgus_reloaded/DGUSDisplay.cpp
new file mode 100644
index 0000000..15b3f5a
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSDisplay.cpp
@@ -0,0 +1,409 @@
+/**
+ * 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 .
+ *
+ */
+
+/* DGUS implementation written by coldtobi in 2019 for Marlin */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_RELOADED)
+
+#include "DGUSDisplay.h"
+
+#include "config/DGUS_Addr.h"
+#include "config/DGUS_Constants.h"
+#include "definition/DGUS_VPList.h"
+
+#include "../ui_api.h"
+#include "../../../gcode/gcode.h"
+
+long map_precise(float x, long in_min, long in_max, long out_min, long out_max) {
+ return LROUND((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min);
+}
+
+uint8_t DGUSDisplay::gui_version = 0;
+uint8_t DGUSDisplay::os_version = 0;
+
+uint8_t DGUSDisplay::volume = 255;
+uint8_t DGUSDisplay::brightness = 100;
+
+DGUSDisplay::rx_datagram_state_t DGUSDisplay::rx_datagram_state = DGUS_IDLE;
+uint8_t DGUSDisplay::rx_datagram_len = 0;
+
+bool DGUSDisplay::initialized = false;
+
+void DGUSDisplay::Loop() {
+ ProcessRx();
+}
+
+void DGUSDisplay::Init() {
+ LCD_SERIAL.begin(LCD_BAUDRATE);
+
+ ReadVersions();
+}
+
+void DGUSDisplay::Read(uint16_t addr, uint8_t size) {
+ WriteHeader(addr, DGUS_READVAR, size);
+
+ LCD_SERIAL.write(size);
+}
+
+void DGUSDisplay::Write(uint16_t addr, const void* data_ptr, uint8_t size) {
+ if (!data_ptr) return;
+
+ WriteHeader(addr, DGUS_WRITEVAR, size);
+
+ const char* data = static_cast(data_ptr);
+
+ while (size--) {
+ LCD_SERIAL.write(*data++);
+ }
+}
+
+void DGUSDisplay::WriteString(uint16_t addr, const void* data_ptr, uint8_t size, bool left, bool right, bool use_space) {
+ if (!data_ptr) return;
+
+ WriteHeader(addr, DGUS_WRITEVAR, size);
+
+ const char* data = static_cast(data_ptr);
+ size_t len = strlen(data);
+ uint8_t left_spaces = 0;
+ uint8_t right_spaces = 0;
+
+ if (len < size) {
+ if (!len) {
+ right_spaces = size;
+ }
+ else if ((left && right) || (!left && !right)) {
+ left_spaces = (size - len) / 2;
+ right_spaces = size - len - left_spaces;
+ }
+ else if (left) {
+ right_spaces = size - len;
+ }
+ else {
+ left_spaces = size - len;
+ }
+ }
+ else {
+ len = size;
+ }
+
+ while (left_spaces--) {
+ LCD_SERIAL.write(' ');
+ }
+ while (len--) {
+ LCD_SERIAL.write(*data++);
+ }
+ while (right_spaces--) {
+ LCD_SERIAL.write(use_space ? ' ' : '\0');
+ }
+}
+
+void DGUSDisplay::WriteStringPGM(uint16_t addr, const void* data_ptr, uint8_t size, bool left, bool right, bool use_space) {
+ if (!data_ptr) return;
+
+ WriteHeader(addr, DGUS_WRITEVAR, size);
+
+ const char* data = static_cast(data_ptr);
+ size_t len = strlen_P(data);
+ uint8_t left_spaces = 0;
+ uint8_t right_spaces = 0;
+
+ if (len < size) {
+ if (!len) {
+ right_spaces = size;
+ }
+ else if ((left && right) || (!left && !right)) {
+ left_spaces = (size - len) / 2;
+ right_spaces = size - len - left_spaces;
+ }
+ else if (left) {
+ right_spaces = size - len;
+ }
+ else {
+ left_spaces = size - len;
+ }
+ }
+ else {
+ len = size;
+ }
+
+ while (left_spaces--) {
+ LCD_SERIAL.write(' ');
+ }
+ while (len--) {
+ LCD_SERIAL.write(pgm_read_byte(data++));
+ }
+ while (right_spaces--) {
+ LCD_SERIAL.write(use_space ? ' ' : '\0');
+ }
+}
+
+void DGUSDisplay::ReadVersions() {
+ if (gui_version != 0 && os_version != 0) return;
+ Read(DGUS_VERSION, 1);
+}
+
+void DGUSDisplay::SwitchScreen(DGUS_Screen screen) {
+ DEBUG_ECHOLNPGM("SwitchScreen ", (uint8_t)screen);
+ const uint8_t command[] = { 0x5A, 0x01, 0x00, (uint8_t)screen };
+ Write(0x84, command, sizeof(command));
+}
+
+void DGUSDisplay::PlaySound(uint8_t start, uint8_t len, uint8_t volume) {
+ if (volume == 0) volume = DGUSDisplay::volume;
+ if (volume == 0) return;
+ DEBUG_ECHOLNPGM("PlaySound ", start, ":", len, "\nVolume ", volume);
+ const uint8_t command[] = { start, len, volume, 0x00 };
+ Write(0xA0, command, sizeof(command));
+}
+
+void DGUSDisplay::EnableControl(DGUS_Screen screen, DGUS_ControlType type, DGUS_Control control) {
+ DEBUG_ECHOLNPGM("EnableControl ", (uint8_t)control, "\nScreen ", (uint8_t)screen, "\nType ", (uint8_t)type);
+
+ const uint8_t command[] = { 0x5A, 0xA5, 0x00, (uint8_t)screen, (uint8_t)control, type, 0x00, 0x01 };
+ Write(0xB0, command, sizeof(command));
+
+ FlushTx();
+ delay(50);
+}
+
+void DGUSDisplay::DisableControl(DGUS_Screen screen, DGUS_ControlType type, DGUS_Control control) {
+ DEBUG_ECHOLNPGM("DisableControl ", (uint8_t)control, "\nScreen ", (uint8_t)screen, "\nType ", (uint8_t)type);
+
+ const uint8_t command[] = { 0x5A, 0xA5, 0x00, (uint8_t)screen, (uint8_t)control, type, 0x00, 0x00 };
+ Write(0xB0, command, sizeof(command));
+
+ FlushTx();
+ delay(50);
+}
+
+uint8_t DGUSDisplay::GetBrightness() {
+ return brightness;
+}
+
+uint8_t DGUSDisplay::GetVolume() {
+ return map_precise(volume, 0, 255, 0, 100);
+}
+
+void DGUSDisplay::SetBrightness(uint8_t new_brightness) {
+ brightness = constrain(new_brightness, 0, 100);
+ new_brightness = map_precise(brightness, 0, 100, 5, 100);
+ DEBUG_ECHOLNPGM("SetBrightness ", new_brightness);
+ const uint8_t command[] = { new_brightness, new_brightness };
+ Write(0x82, command, sizeof(command));
+}
+
+void DGUSDisplay::SetVolume(uint8_t new_volume) {
+ volume = map_precise(constrain(new_volume, 0, 100), 0, 100, 0, 255);
+ DEBUG_ECHOLNPGM("SetVolume ", volume);
+ const uint8_t command[] = { volume, 0x00 };
+ Write(0xA1, command, sizeof(command));
+}
+
+void DGUSDisplay::ProcessRx() {
+
+ #if ENABLED(LCD_SERIAL_STATS_RX_BUFFER_OVERRUNS)
+ if (!LCD_SERIAL.available() && LCD_SERIAL.buffer_overruns()) {
+ // Overrun, but reset the flag only when the buffer is empty
+ // We want to extract as many as valid datagrams possible...
+ DEBUG_ECHOPGM("OVFL");
+ rx_datagram_state = DGUS_IDLE;
+ //LCD_SERIAL.reset_rx_overun();
+ LCD_SERIAL.flush();
+ }
+ #endif
+
+ uint8_t receivedbyte;
+ while (LCD_SERIAL.available()) {
+ switch (rx_datagram_state) {
+
+ case DGUS_IDLE: // Waiting for the first header byte
+ receivedbyte = LCD_SERIAL.read();
+ DEBUG_ECHOPGM("< ", receivedbyte);
+ if (DGUS_HEADER1 == receivedbyte) rx_datagram_state = DGUS_HEADER1_SEEN;
+ break;
+
+ case DGUS_HEADER1_SEEN: // Waiting for the second header byte
+ receivedbyte = LCD_SERIAL.read();
+ DEBUG_ECHOPGM(" ", receivedbyte);
+ rx_datagram_state = (DGUS_HEADER2 == receivedbyte) ? DGUS_HEADER2_SEEN : DGUS_IDLE;
+ break;
+
+ case DGUS_HEADER2_SEEN: // Waiting for the length byte
+ rx_datagram_len = LCD_SERIAL.read();
+ DEBUG_ECHOPGM(" (", rx_datagram_len, ") ");
+
+ // Telegram min len is 3 (command and one word of payload)
+ rx_datagram_state = WITHIN(rx_datagram_len, 3, DGUS_RX_BUFFER_SIZE) ? DGUS_WAIT_TELEGRAM : DGUS_IDLE;
+ break;
+
+ case DGUS_WAIT_TELEGRAM: // wait for complete datagram to arrive.
+ if (LCD_SERIAL.available() < rx_datagram_len) return;
+
+ initialized = true; // We've talked to it, so we defined it as initialized.
+ uint8_t command = LCD_SERIAL.read();
+
+ DEBUG_ECHOPGM("# ", command);
+
+ uint8_t readlen = rx_datagram_len - 1; // command is part of len.
+ unsigned char tmp[rx_datagram_len - 1];
+ unsigned char *ptmp = tmp;
+
+ while (readlen--) {
+ receivedbyte = LCD_SERIAL.read();
+ DEBUG_ECHOPGM(" ", receivedbyte);
+ *ptmp++ = receivedbyte;
+ }
+ DEBUG_ECHOPGM(" # ");
+ // mostly we'll get this: 5A A5 03 82 4F 4B -- ACK on 0x82, so discard it.
+ if (command == DGUS_WRITEVAR && 'O' == tmp[0] && 'K' == tmp[1]) {
+ DEBUG_ECHOLNPGM(">");
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ /* AutoUpload, (and answer to) Command 0x83 :
+ | tmp[0 1 2 3 4 ... ]
+ | Example 5A A5 06 83 20 01 01 78 01 ……
+ | / / | | \ / | \ \
+ | Header | | | | \_____\_ DATA (Words!)
+ | DatagramLen / VPAdr |
+ | Command DataLen (in Words) */
+ if (command == DGUS_READVAR) {
+ const uint16_t addr = tmp[0] << 8 | tmp[1];
+ const uint8_t dlen = tmp[2] << 1; // Convert to Bytes. (Display works with words)
+ DEBUG_ECHOPGM("addr=", addr, " dlen=", dlen, "> ");
+
+ if (addr == DGUS_VERSION && dlen == 2) {
+ DEBUG_ECHOLNPGM("VERSIONS");
+ gui_version = tmp[3];
+ os_version = tmp[4];
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ DGUS_VP vp;
+ if (!DGUS_PopulateVP((DGUS_Addr)addr, &vp)) {
+ DEBUG_ECHOLNPGM("VP not found");
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ if (!vp.rx_handler) {
+ DEBUG_ECHOLNPGM("VP found, no handler.");
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ gcode.reset_stepper_timeout();
+
+ if (!vp.size) {
+ DEBUG_EOL();
+ vp.rx_handler(vp, nullptr);
+
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ if (vp.flags & VPFLAG_RXSTRING) {
+ unsigned char buffer[vp.size];
+ memset(buffer, 0, vp.size);
+
+ for (uint8_t i = 0; i < dlen; i++) {
+ if (i >= vp.size) break;
+
+ if (i + 1 < dlen && tmp[i + 3] == 0xFF && tmp[i + 4] == 0xFF)
+ break;
+
+ buffer[i] = tmp[i + 3];
+ }
+
+ DEBUG_EOL();
+ vp.rx_handler(vp, buffer);
+
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ if (dlen != vp.size) {
+ DEBUG_ECHOLNPGM("VP found, size mismatch.");
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ DEBUG_EOL();
+ vp.rx_handler(vp, &tmp[3]);
+
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+
+ DEBUG_ECHOLNPGM(">");
+ rx_datagram_state = DGUS_IDLE;
+ break;
+ }
+ }
+}
+
+size_t DGUSDisplay::GetFreeTxBuffer() {
+ #ifdef LCD_SERIAL_GET_TX_BUFFER_FREE
+ return LCD_SERIAL_GET_TX_BUFFER_FREE();
+ #else
+ return SIZE_MAX;
+ #endif
+}
+
+void DGUSDisplay::FlushTx() {
+ #ifdef ARDUINO_ARCH_STM32
+ LCD_SERIAL.flush();
+ #else
+ LCD_SERIAL.flushTX();
+ #endif
+}
+
+void DGUSDisplay::WriteHeader(uint16_t addr, uint8_t command, uint8_t len) {
+ LCD_SERIAL.write(DGUS_HEADER1);
+ LCD_SERIAL.write(DGUS_HEADER2);
+ LCD_SERIAL.write(len + 3);
+ LCD_SERIAL.write(command);
+ LCD_SERIAL.write(addr >> 8);
+ LCD_SERIAL.write(addr & 0xFF);
+}
+
+bool DGUS_PopulateVP(const DGUS_Addr addr, DGUS_VP * const buffer) {
+ const DGUS_VP *ret = vp_list;
+
+ do {
+ const uint16_t *paddr = (uint16_t *)(&ret->addr);
+ const uint16_t addrcheck = pgm_read_word(paddr);
+ if (addrcheck == 0) break;
+ if ((DGUS_Addr)addrcheck == addr) {
+ memcpy_P(buffer, ret, sizeof(*ret));
+ return true;
+ }
+ } while (++ret);
+ DEBUG_ECHOLNPGM("VP not found: ", (uint16_t)addr);
+ return false;
+}
+
+#endif // DGUS_LCD_UI_RELOADED
diff --git a/src/lcd/extui/dgus_reloaded/DGUSDisplay.h b/src/lcd/extui/dgus_reloaded/DGUSDisplay.h
new file mode 100644
index 0000000..fa5bf30
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSDisplay.h
@@ -0,0 +1,174 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+/* DGUS implementation written by coldtobi in 2019 for Marlin */
+
+#include "config/DGUS_Screen.h"
+#include "config/DGUS_Control.h"
+#include "definition/DGUS_VP.h"
+
+#include "../../../inc/MarlinConfigPre.h"
+#include "../../../MarlinCore.h"
+
+#define DEBUG_OUT ENABLED(DEBUG_DGUSLCD)
+#include "../../../core/debug_out.h"
+
+#define Swap16(val) ((uint16_t)(((uint16_t)(val) >> 8) |\
+ ((uint16_t)(val) << 8)))
+
+// Low-Level access to the display.
+class DGUSDisplay {
+public:
+
+ enum DGUS_ControlType : uint8_t {
+ VARIABLE_DATA_INPUT = 0x00,
+ POPUP_WINDOW = 0x01,
+ INCREMENTAL_ADJUST = 0x02,
+ SLIDER_ADJUST = 0x03,
+ RTC_SETTINGS = 0x04,
+ RETURN_KEY_CODE = 0x05,
+ TEXT_INPUT = 0x06,
+ FIRMWARE_SETTINGS = 0x07
+ };
+
+ DGUSDisplay() = default;
+
+ static void Init();
+
+ static void Read(uint16_t addr, uint8_t size);
+ static void Write(uint16_t addr, const void* data_ptr, uint8_t size);
+
+ static void WriteString(uint16_t addr, const void* data_ptr, uint8_t size, bool left = true, bool right = false, bool use_space = true);
+ static void WriteStringPGM(uint16_t addr, const void* data_ptr, uint8_t size, bool left = true, bool right = false, bool use_space = true);
+
+ template
+ static void Write(uint16_t addr, T data) {
+ Write(addr, static_cast(&data), sizeof(T));
+ }
+
+ // Until now I did not need to actively read from the display. That's why there is no ReadVariable
+ // (I extensively use the auto upload of the display)
+
+ // Read GUI and OS version from screen
+ static void ReadVersions();
+
+ // Force display into another screen.
+ static void SwitchScreen(DGUS_Screen screen);
+ // Play sounds using the display speaker.
+ // start: position at which the sound was stored on the display.
+ // len: how many sounds to play. Sounds will play consecutively from start to start+len-1.
+ // volume: playback volume. 0 keeps the current volume.
+ static void PlaySound(uint8_t start, uint8_t len = 1, uint8_t volume = 0);
+ // Enable/disable a specific touch control.
+ // type: control type.
+ // control: index of the control on the page (set during screen development).
+ static void EnableControl(DGUS_Screen screen, DGUS_ControlType type, DGUS_Control control);
+ static void DisableControl(DGUS_Screen screen, DGUS_ControlType type, DGUS_Control control);
+
+ static uint8_t GetBrightness();
+ static uint8_t GetVolume();
+
+ // Set the display brightness/volume, ranging 0 - 100
+ static void SetBrightness(uint8_t brightness);
+ static void SetVolume(uint8_t volume);
+
+ // Periodic tasks, eg. Rx-Queue handling.
+ static void Loop();
+
+ // Helper for users of this class to estimate if an interaction would be blocking.
+ static size_t GetFreeTxBuffer();
+ static void FlushTx();
+
+ // Checks two things: Can we confirm the presence of the display and has we initialized it.
+ // (both boils down that the display answered to our chatting)
+ static bool IsInitialized() {
+ return initialized;
+ }
+
+ static uint8_t gui_version;
+ static uint8_t os_version;
+
+ template
+ static T SwapBytes(const T value) {
+ union {
+ T val;
+ char byte[sizeof(T)];
+ } src, dst;
+
+ src.val = value;
+ LOOP_L_N(i, sizeof(T)) dst.byte[i] = src.byte[sizeof(T) - i - 1];
+ return dst.val;
+ }
+
+ template
+ T_out FromFixedPoint(const T_in value) {
+ return (T_out)((float)value / POW(10, decimals));
+ }
+
+ template
+ T_out ToFixedPoint(const T_in value) {
+ return (T_out)LROUND((float)value * POW(10, decimals));
+ }
+
+private:
+ enum dgus_header : uint8_t {
+ DGUS_HEADER1 = 0x5A,
+ DGUS_HEADER2 = 0xA5
+ };
+
+ enum dgus_command : uint8_t {
+ DGUS_WRITEVAR = 0x82,
+ DGUS_READVAR = 0x83
+ };
+
+ enum rx_datagram_state_t : uint8_t {
+ DGUS_IDLE, //< waiting for DGUS_HEADER1.
+ DGUS_HEADER1_SEEN, //< DGUS_HEADER1 received
+ DGUS_HEADER2_SEEN, //< DGUS_HEADER2 received
+ DGUS_WAIT_TELEGRAM, //< LEN received, Waiting for to receive all bytes.
+ };
+
+ enum dgus_system_addr : uint16_t {
+ DGUS_VERSION = 0x000f // OS/GUI version
+ };
+
+ static void WriteHeader(uint16_t addr, uint8_t command, uint8_t len);
+ static void ProcessRx();
+
+ static uint8_t volume;
+ static uint8_t brightness;
+
+ static rx_datagram_state_t rx_datagram_state;
+ static uint8_t rx_datagram_len;
+
+ static bool initialized;
+};
+
+template<> inline uint16_t DGUSDisplay::SwapBytes(const uint16_t value) {
+ return ((value << 8) | (value >> 8));
+}
+
+extern DGUSDisplay dgus_display;
+
+/// Helper to populate a DGUS_VP for a given VP. Return false if not found.
+extern bool DGUS_PopulateVP(const DGUS_Addr addr, DGUS_VP * const buffer);
diff --git a/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp b/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp
new file mode 100644
index 0000000..88fe30a
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSRxHandler.cpp
@@ -0,0 +1,1043 @@
+/**
+ * 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 .
+ *
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_RELOADED)
+
+#include "DGUSRxHandler.h"
+
+#include "DGUSScreenHandler.h"
+#include "config/DGUS_Screen.h"
+
+#include "../ui_api.h"
+#include "../../../core/language.h"
+#include "../../../module/temperature.h"
+#include "../../../module/printcounter.h"
+#include "../../../module/stepper.h"
+#include "../../../gcode/queue.h"
+#if ENABLED(ADVANCED_PAUSE_FEATURE)
+ #include "../../../feature/pause.h"
+#endif
+#if ENABLED(POWER_LOSS_RECOVERY)
+ #include "../../../feature/powerloss.h"
+#endif
+
+void DGUSRxHandler::ScreenChange(DGUS_VP &vp, void *data_ptr) {
+ const DGUS_Screen screen = (DGUS_Screen)((uint8_t*)data_ptr)[1];
+
+ if (vp.addr == DGUS_Addr::SCREENCHANGE_SD) {
+ #if ENABLED(SDSUPPORT)
+ IF_DISABLED(HAS_SD_DETECT, card.mount());
+
+ if (!ExtUI::isMediaInserted()) {
+ dgus_screen_handler.SetStatusMessage(GET_TEXT_F(MSG_NO_MEDIA));
+ return;
+ }
+
+ card.cdroot();
+ #else
+ dgus_screen_handler.SetStatusMessage(GET_TEXT_F(MSG_NO_MEDIA));
+ return;
+ #endif
+ }
+
+ if (vp.addr == DGUS_Addr::SCREENCHANGE_Idle
+ && (ExtUI::isPrinting() || ExtUI::isPrintingPaused())) {
+ dgus_screen_handler.SetStatusMessage(F("Impossible while printing"));
+ return;
+ }
+
+ if (vp.addr == DGUS_Addr::SCREENCHANGE_Printing
+ && (!ExtUI::isPrinting() && !ExtUI::isPrintingPaused())) {
+ dgus_screen_handler.SetStatusMessage(F("Impossible while idle"));
+ return;
+ }
+
+ dgus_screen_handler.TriggerScreenChange(screen);
+}
+
+#if ENABLED(SDSUPPORT)
+ void DGUSRxHandler::Scroll(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Scroll scroll = (DGUS_Data::Scroll)((uint8_t*)data_ptr)[1];
+
+ switch (scroll) {
+ case DGUS_Data::Scroll::GO_BACK:
+ if (dgus_screen_handler.filelist.isAtRootDir()) {
+ return;
+ }
+
+ dgus_screen_handler.filelist_offset = 0;
+ dgus_screen_handler.filelist_selected = -1;
+ dgus_screen_handler.filelist.upDir();
+ break;
+ case DGUS_Data::Scroll::UP:
+ if (dgus_screen_handler.filelist_offset < 1) {
+ return;
+ }
+
+ --dgus_screen_handler.filelist_offset;
+ break;
+ case DGUS_Data::Scroll::DOWN:
+ if (dgus_screen_handler.filelist_offset + 1 + DGUS_FILE_COUNT > dgus_screen_handler.filelist.count()) {
+ return;
+ }
+
+ ++dgus_screen_handler.filelist_offset;
+ break;
+ }
+
+ dgus_screen_handler.TriggerFullUpdate();
+ }
+
+ void DGUSRxHandler::SelectFile(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const uint8_t index = ((uint8_t*)data_ptr)[1];
+
+ if (!dgus_screen_handler.filelist.seek(dgus_screen_handler.filelist_offset + index)) {
+ return;
+ }
+
+ if (dgus_screen_handler.filelist.isDir()) {
+ dgus_screen_handler.filelist_offset = 0;
+ dgus_screen_handler.filelist_selected = -1;
+ dgus_screen_handler.filelist.changeDir(dgus_screen_handler.filelist.filename());
+ }
+ else {
+ dgus_screen_handler.filelist_selected = dgus_screen_handler.filelist_offset + index;
+ }
+
+ dgus_screen_handler.TriggerFullUpdate();
+ }
+
+ void DGUSRxHandler::PrintFile(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+ UNUSED(data_ptr);
+
+ if (dgus_screen_handler.filelist_selected < 0) {
+ dgus_screen_handler.SetStatusMessage(F("No file selected"));
+ return;
+ }
+
+ if (!dgus_screen_handler.filelist.seek(dgus_screen_handler.filelist_selected)
+ || dgus_screen_handler.filelist.isDir()) {
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ ExtUI::printFile(dgus_screen_handler.filelist.shortFilename());
+ dgus_screen_handler.TriggerScreenChange(DGUS_Screen::PRINT_STATUS);
+ }
+#endif // SDSUPPORT
+
+void DGUSRxHandler::PrintAbort(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Popup result = (DGUS_Data::Popup)((uint8_t*)data_ptr)[1];
+
+ if (result != DGUS_Data::Popup::CONFIRMED) {
+ return;
+ }
+
+ if (!ExtUI::isPrinting() && !ExtUI::isPrintingPaused()) {
+ dgus_screen_handler.TriggerFullUpdate();
+ return;
+ }
+
+ ExtUI::stopPrint();
+}
+
+void DGUSRxHandler::PrintPause(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Popup result = (DGUS_Data::Popup)((uint8_t*)data_ptr)[1];
+
+ if (result != DGUS_Data::Popup::CONFIRMED) {
+ return;
+ }
+
+ if (!ExtUI::isPrinting()) {
+ dgus_screen_handler.TriggerFullUpdate();
+ return;
+ }
+
+ ExtUI::pausePrint();
+}
+
+void DGUSRxHandler::PrintResume(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Popup result = (DGUS_Data::Popup)((uint8_t*)data_ptr)[1];
+
+ if (result != DGUS_Data::Popup::CONFIRMED) {
+ return;
+ }
+
+ if (!ExtUI::isPrintingPaused()) {
+ dgus_screen_handler.TriggerFullUpdate();
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ ExtUI::resumePrint();
+}
+
+void DGUSRxHandler::Feedrate(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const int16_t feedrate = Swap16(*(int16_t*)data_ptr);
+
+ ExtUI::setFeedrate_percent(feedrate);
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::Flowrate(DGUS_VP &vp, void *data_ptr) {
+ const int16_t flowrate = Swap16(*(int16_t*)data_ptr);
+
+ switch (vp.addr) {
+ default: return;
+ case DGUS_Addr::ADJUST_SetFlowrate_CUR:
+ ExtUI::setFlow_percent(flowrate, TERN(HAS_MULTI_EXTRUDER, ExtUI::getActiveTool(), ExtUI::E0));
+ break;
+ #if HAS_MULTI_EXTRUDER
+ case DGUS_Addr::ADJUST_SetFlowrate_E0:
+ ExtUI::setFlow_percent(flowrate, ExtUI::E0);
+ break;
+ case DGUS_Addr::ADJUST_SetFlowrate_E1:
+ ExtUI::setFlow_percent(flowrate, ExtUI::E1);
+ break;
+ #endif
+ }
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::BabystepSet(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const int16_t data = Swap16(*(int16_t*)data_ptr);
+ const float offset = dgus_display.FromFixedPoint(data);
+
+ const int16_t steps = ExtUI::mmToWholeSteps(offset - ExtUI::getZOffset_mm(), ExtUI::Z);
+
+ ExtUI::smartAdjustAxis_steps(steps, ExtUI::Z, true);
+
+ dgus_screen_handler.TriggerEEPROMSave();
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::Babystep(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Adjust adjust = (DGUS_Data::Adjust)((uint8_t*)data_ptr)[1];
+ int16_t steps;
+
+ switch (adjust) {
+ default: return;
+ case DGUS_Data::Adjust::INCREMENT:
+ steps = ExtUI::mmToWholeSteps(DGUS_PRINT_BABYSTEP, ExtUI::Z);
+ break;
+ case DGUS_Data::Adjust::DECREMENT:
+ steps = ExtUI::mmToWholeSteps(-DGUS_PRINT_BABYSTEP, ExtUI::Z);
+ break;
+ }
+
+ ExtUI::smartAdjustAxis_steps(steps, ExtUI::Z, true);
+
+ dgus_screen_handler.TriggerEEPROMSave();
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::TempPreset(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::TempPreset preset = (DGUS_Data::TempPreset)((uint8_t*)data_ptr)[1];
+
+ switch (preset) {
+ case DGUS_Data::TempPreset::PLA:
+ #if HOTENDS < 2
+ ExtUI::setTargetTemp_celsius(DGUS_PLA_TEMP_HOTEND, ExtUI::H0);
+ #else
+ ExtUI::setTargetTemp_celsius(DGUS_PLA_TEMP_HOTEND, ExtUI::getActiveTool());
+ #endif
+ ExtUI::setTargetTemp_celsius(DGUS_PLA_TEMP_BED, ExtUI::BED);
+ break;
+ case DGUS_Data::TempPreset::ABS:
+ #if HOTENDS < 2
+ ExtUI::setTargetTemp_celsius(DGUS_ABS_TEMP_HOTEND, ExtUI::H0);
+ #else
+ ExtUI::setTargetTemp_celsius(DGUS_ABS_TEMP_HOTEND, ExtUI::getActiveTool());
+ #endif
+ ExtUI::setTargetTemp_celsius(DGUS_ABS_TEMP_BED, ExtUI::BED);
+ break;
+ case DGUS_Data::TempPreset::PETG:
+ #if HOTENDS < 2
+ ExtUI::setTargetTemp_celsius(DGUS_PETG_TEMP_HOTEND, ExtUI::H0);
+ #else
+ ExtUI::setTargetTemp_celsius(DGUS_PETG_TEMP_HOTEND, ExtUI::getActiveTool());
+ #endif
+ ExtUI::setTargetTemp_celsius(DGUS_PETG_TEMP_BED, ExtUI::BED);
+ break;
+ }
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::TempTarget(DGUS_VP &vp, void *data_ptr) {
+ const int16_t temp = Swap16(*(int16_t*)data_ptr);
+
+ switch (vp.addr) {
+ default: return;
+ case DGUS_Addr::TEMP_SetTarget_Bed:
+ ExtUI::setTargetTemp_celsius(temp, ExtUI::BED);
+ break;
+ case DGUS_Addr::TEMP_SetTarget_H0:
+ ExtUI::setTargetTemp_celsius(temp, ExtUI::H0);
+ break;
+ #if HAS_MULTI_HOTEND
+ case DGUS_Addr::TEMP_SetTarget_H1:
+ ExtUI::setTargetTemp_celsius(temp, ExtUI::H1);
+ break;
+ #endif
+ }
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::TempCool(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Heater heater = (DGUS_Data::Heater)Swap16(*(uint16_t*)data_ptr);
+
+ switch (heater) {
+ default: return;
+ case DGUS_Data::Heater::ALL:
+ ExtUI::setTargetTemp_celsius(0, ExtUI::BED);
+ ExtUI::setTargetTemp_celsius(0, ExtUI::H0);
+ #if HAS_MULTI_HOTEND
+ ExtUI::setTargetTemp_celsius(0, ExtUI::H1);
+ #endif
+ break;
+ case DGUS_Data::Heater::BED:
+ ExtUI::setTargetTemp_celsius(0, ExtUI::BED);
+ break;
+ case DGUS_Data::Heater::H0:
+ ExtUI::setTargetTemp_celsius(0, ExtUI::H0);
+ break;
+ #if HAS_MULTI_HOTEND
+ case DGUS_Data::Heater::H1:
+ ExtUI::setTargetTemp_celsius(0, ExtUI::H1);
+ break;
+ #endif
+ }
+
+ dgus_screen_handler.SetStatusMessage(F("Cooling..."));
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::Steppers(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Control control = (DGUS_Data::Control)((uint8_t*)data_ptr)[1];
+
+ switch (control) {
+ case DGUS_Data::Control::ENABLE:
+ stepper.enable_all_steppers();
+ break;
+ case DGUS_Data::Control::DISABLE:
+ stepper.disable_all_steppers();
+ break;
+ }
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::ZOffset(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ if (!ExtUI::isAxisPositionKnown(ExtUI::Z)) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_HOMING_REQUIRED));
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ const int16_t data = Swap16(*(int16_t*)data_ptr);
+ const float offset = dgus_display.FromFixedPoint(data);
+
+ const int16_t steps = ExtUI::mmToWholeSteps(offset - ExtUI::getZOffset_mm(), ExtUI::Z);
+
+ ExtUI::smartAdjustAxis_steps(steps, ExtUI::Z, true);
+
+ dgus_screen_handler.TriggerEEPROMSave();
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::ZOffsetStep(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ if (!ExtUI::isAxisPositionKnown(ExtUI::Z)) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_HOMING_REQUIRED));
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ const DGUS_Data::Adjust adjust = (DGUS_Data::Adjust)((uint8_t*)data_ptr)[1];
+ int16_t steps;
+
+ switch (dgus_screen_handler.offset_steps) {
+ default: return;
+ case DGUS_Data::StepSize::MMP1:
+ steps = ExtUI::mmToWholeSteps((adjust == DGUS_Data::Adjust::INCREMENT ? 0.1f : -0.1f), ExtUI::Z);
+ break;
+ case DGUS_Data::StepSize::MMP01:
+ steps = ExtUI::mmToWholeSteps((adjust == DGUS_Data::Adjust::INCREMENT ? 0.01f : -0.01f), ExtUI::Z);
+ break;
+ }
+
+ ExtUI::smartAdjustAxis_steps(steps, ExtUI::Z, true);
+
+ dgus_screen_handler.TriggerEEPROMSave();
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::ZOffsetSetStep(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::StepSize size = (DGUS_Data::StepSize)((uint8_t*)data_ptr)[1];
+
+ dgus_screen_handler.offset_steps = size;
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::MoveToPoint(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ if (!ExtUI::isPositionKnown()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_HOMING_REQUIRED));
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ const uint8_t point = ((uint8_t*)data_ptr)[1];
+ constexpr float lfrb[4] = BED_TRAMMING_INSET_LFRB;
+ float x, y;
+
+ switch (point) {
+ default: return;
+ case 1:
+ x = DGUS_LEVEL_CENTER_X;
+ y = DGUS_LEVEL_CENTER_Y;
+ break;
+ case 2:
+ x = X_MIN_POS + lfrb[0];
+ y = Y_MIN_POS + lfrb[1];
+ break;
+ case 3:
+ x = X_MAX_POS - lfrb[2];
+ y = Y_MIN_POS + lfrb[1];
+ break;
+ case 4:
+ x = X_MAX_POS - lfrb[2];
+ y = Y_MAX_POS - lfrb[3];
+ break;
+ case 5:
+ x = X_MIN_POS + lfrb[0];
+ y = Y_MAX_POS - lfrb[3];
+ break;
+ }
+
+ if (ExtUI::getAxisPosition_mm(ExtUI::Z) < Z_MIN_POS + BED_TRAMMING_Z_HOP) {
+ ExtUI::setAxisPosition_mm(Z_MIN_POS + BED_TRAMMING_Z_HOP, ExtUI::Z);
+ }
+ ExtUI::setAxisPosition_mm(x, ExtUI::X);
+ ExtUI::setAxisPosition_mm(y, ExtUI::Y);
+ ExtUI::setAxisPosition_mm(Z_MIN_POS + BED_TRAMMING_HEIGHT, ExtUI::Z);
+}
+
+void DGUSRxHandler::Probe(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+ UNUSED(data_ptr);
+
+ #if ENABLED(MESH_BED_LEVELING)
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_ABL_REQUIRED));
+ return;
+ #endif
+
+ if (!ExtUI::isPositionKnown()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_HOMING_REQUIRED));
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ dgus_screen_handler.TriggerScreenChange(DGUS_Screen::LEVELING_PROBING);
+
+ #if ENABLED(AUTO_BED_LEVELING_UBL)
+ queue.enqueue_now(F("G29P1\nG29P3\nG29P5C"));
+ #else
+ queue.enqueue_now(F("G29"));
+ #endif
+ queue.enqueue_now_P(DGUS_CMD_EEPROM_SAVE);
+}
+
+void DGUSRxHandler::DisableABL(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+ UNUSED(data_ptr);
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ ExtUI::setLevelingActive(false);
+
+ dgus_screen_handler.TriggerEEPROMSave();
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::FilamentSelect(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Extruder extruder = (DGUS_Data::Extruder)Swap16(*(uint16_t*)data_ptr);
+
+ switch (extruder) {
+ default: return;
+ case DGUS_Data::Extruder::CURRENT:
+ case DGUS_Data::Extruder::E0:
+ E_TERN_(case DGUS_Data::Extruder::E1:)
+ dgus_screen_handler.filament_extruder = extruder;
+ break;
+ }
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::FilamentLength(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const uint16_t length = Swap16(*(uint16_t*)data_ptr);
+
+ dgus_screen_handler.filament_length = constrain(length, 0, EXTRUDE_MAXLENGTH);
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::FilamentMove(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ ExtUI::extruder_t extruder;
+
+ switch (dgus_screen_handler.filament_extruder) {
+ default: return;
+ case DGUS_Data::Extruder::CURRENT:
+ #if HAS_MULTI_EXTRUDER
+ extruder = ExtUI::getActiveTool();
+ break;
+ #endif
+ case DGUS_Data::Extruder::E0:
+ extruder = ExtUI::E0;
+ break;
+ #if HAS_MULTI_EXTRUDER
+ case DGUS_Data::Extruder::E1:
+ extruder = ExtUI::E1;
+ break;
+ #endif
+ }
+
+ if (ExtUI::getActualTemp_celsius(extruder) < (float)EXTRUDE_MINTEMP) {
+ dgus_screen_handler.SetStatusMessage(F("Temperature too low"));
+ return;
+ }
+
+ const DGUS_Data::FilamentMove move = (DGUS_Data::FilamentMove)((uint8_t*)data_ptr)[1];
+
+ switch (move) {
+ case DGUS_Data::FilamentMove::RETRACT:
+ UI_DECREMENT_BY(AxisPosition_mm, (float)dgus_screen_handler.filament_length, extruder);
+ break;
+ case DGUS_Data::FilamentMove::EXTRUDE:
+ UI_INCREMENT_BY(AxisPosition_mm, (float)dgus_screen_handler.filament_length, extruder);
+ break;
+ }
+}
+
+void DGUSRxHandler::Home(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ DGUS_Data::Axis axis = (DGUS_Data::Axis)((uint8_t*)data_ptr)[1];
+
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 1);
+ dgus_screen_handler.SetMessageLinePGM(DGUS_MSG_HOMING, 2);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 3);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 4);
+ dgus_screen_handler.ShowWaitScreen(dgus_screen_handler.GetCurrentScreen());
+
+ switch (axis) {
+ case DGUS_Data::Axis::X_Y_Z:
+ queue.enqueue_now(F("G28XYZ"));
+ break;
+ case DGUS_Data::Axis::X_Y:
+ queue.enqueue_now(F("G28XY"));
+ break;
+ case DGUS_Data::Axis::Z:
+ queue.enqueue_now(F("G28Z"));
+ break;
+ }
+}
+
+void DGUSRxHandler::Move(DGUS_VP &vp, void *data_ptr) {
+ const int16_t data = Swap16(*(int16_t*)data_ptr);
+ const float position = dgus_display.FromFixedPoint(data);
+ ExtUI::axis_t axis;
+
+ switch (vp.addr) {
+ default: return;
+ case DGUS_Addr::MOVE_SetX:
+ axis = ExtUI::X;
+ break;
+ case DGUS_Addr::MOVE_SetY:
+ axis = ExtUI::Y;
+ break;
+ case DGUS_Addr::MOVE_SetZ:
+ axis = ExtUI::Z;
+ break;
+ }
+
+ if (!ExtUI::isAxisPositionKnown(axis)) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_HOMING_REQUIRED));
+ return;
+ }
+
+ ExtUI::setAxisPosition_mm(position, axis);
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::MoveStep(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ float offset;
+
+ switch (dgus_screen_handler.move_steps) {
+ default: return;
+ case DGUS_Data::StepSize::MM10:
+ offset = 10.0f;
+ break;
+ case DGUS_Data::StepSize::MM1:
+ offset = 1.0f;
+ break;
+ case DGUS_Data::StepSize::MMP1:
+ offset = 0.1f;
+ break;
+ }
+
+ const DGUS_Data::MoveDirection direction = (DGUS_Data::MoveDirection)((uint8_t*)data_ptr)[1];
+ ExtUI::axis_t axis;
+
+ switch (direction) {
+ default: return;
+ case DGUS_Data::MoveDirection::XP:
+ axis = ExtUI::X;
+ break;
+ case DGUS_Data::MoveDirection::XM:
+ axis = ExtUI::X;
+ offset = -offset;
+ break;
+ case DGUS_Data::MoveDirection::YP:
+ axis = ExtUI::Y;
+ break;
+ case DGUS_Data::MoveDirection::YM:
+ axis = ExtUI::Y;
+ offset = -offset;
+ break;
+ case DGUS_Data::MoveDirection::ZP:
+ axis = ExtUI::Z;
+ break;
+ case DGUS_Data::MoveDirection::ZM:
+ axis = ExtUI::Z;
+ offset = -offset;
+ break;
+ }
+
+ if (!ExtUI::isAxisPositionKnown(axis)) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_HOMING_REQUIRED));
+ return;
+ }
+
+ UI_INCREMENT_BY(AxisPosition_mm, offset, axis);
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::MoveSetStep(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::StepSize size = (DGUS_Data::StepSize)((uint8_t*)data_ptr)[1];
+
+ dgus_screen_handler.move_steps = size;
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::GcodeClear(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+ UNUSED(data_ptr);
+
+ ZERO(dgus_screen_handler.gcode);
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::GcodeExecute(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+ UNUSED(data_ptr);
+
+ if (!strlen(dgus_screen_handler.gcode)) {
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 1);
+ dgus_screen_handler.SetMessageLinePGM(PSTR("Executing command..."), 2);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 3);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 4);
+ dgus_screen_handler.ShowWaitScreen(DGUS_Screen::GCODE);
+
+ queue.enqueue_one_now(dgus_screen_handler.gcode);
+}
+
+void DGUSRxHandler::ResetEEPROM(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Popup result = (DGUS_Data::Popup)((uint8_t*)data_ptr)[1];
+
+ if (result != DGUS_Data::Popup::CONFIRMED) {
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ queue.enqueue_now(F("M502"));
+ queue.enqueue_now_P(DGUS_CMD_EEPROM_SAVE);
+}
+
+void DGUSRxHandler::SettingsExtra(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Extra extra = (DGUS_Data::Extra)((uint8_t*)data_ptr)[1];
+
+ switch (extra) {
+ default: return;
+ case DGUS_Data::Extra::BUTTON1:
+ #if ENABLED(BLTOUCH)
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ queue.enqueue_now(F(DGUS_RESET_BLTOUCH));
+ #else
+ dgus_screen_handler.TriggerScreenChange(DGUS_Screen::INFOS);
+ #endif
+ break;
+ #if ENABLED(BLTOUCH)
+ case DGUS_Data::Extra::BUTTON2:
+ dgus_screen_handler.TriggerScreenChange(DGUS_Screen::INFOS);
+ break;
+ #endif
+ }
+}
+
+void DGUSRxHandler::PIDSelect(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Heater heater = (DGUS_Data::Heater)Swap16(*(uint16_t*)data_ptr);
+
+ switch (heater) {
+ default: return;
+ case DGUS_Data::Heater::BED:
+ dgus_screen_handler.pid_temp = DGUS_PLA_TEMP_BED;
+ dgus_screen_handler.pid_heater = heater;
+ break;
+ case DGUS_Data::Heater::H0:
+ #if HAS_MULTI_HOTEND
+ case DGUS_Data::Heater::H1:
+ #endif
+ dgus_screen_handler.pid_temp = DGUS_PLA_TEMP_HOTEND;
+ dgus_screen_handler.pid_heater = heater;
+ break;
+ }
+
+ dgus_screen_handler.pid_cycles = 5;
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::PIDSetTemp(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ uint16_t temp = Swap16(*(uint16_t*)data_ptr);
+
+ switch (dgus_screen_handler.pid_heater) {
+ default: return;
+ case DGUS_Data::Heater::BED:
+ temp = constrain(temp, BED_MINTEMP, BED_MAX_TARGET);
+ break;
+ case DGUS_Data::Heater::H0:
+ temp = constrain(temp, HEATER_0_MINTEMP, (HEATER_0_MAXTEMP - HOTEND_OVERSHOOT));
+ break;
+ #if HAS_MULTI_HOTEND
+ case DGUS_Data::Heater::H1:
+ temp = constrain(temp, HEATER_1_MINTEMP, (HEATER_1_MAXTEMP - HOTEND_OVERSHOOT));
+ break;
+ #endif
+ }
+
+ dgus_screen_handler.pid_temp = temp;
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::PIDRun(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+ UNUSED(data_ptr);
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ heater_id_t heater;
+ uint8_t cycles = constrain(dgus_screen_handler.pid_cycles, 3, 10);
+
+ switch (dgus_screen_handler.pid_heater) {
+ default: return;
+ case DGUS_Data::Heater::BED:
+ #if ENABLED(PIDTEMPBED)
+ heater = H_BED;
+ break;
+ #else
+ dgus_screen_handler.SetStatusMessage(F("Bed PID disabled"));
+ return;
+ #endif
+ case DGUS_Data::Heater::H0:
+ #if ENABLED(PIDTEMP)
+ heater = H_E0;
+ break;
+ #else
+ dgus_screen_handler.SetStatusMessage(F("PID disabled"));
+ return;
+ #endif
+ #if HAS_MULTI_HOTEND
+ case DGUS_Data::Heater::H1:
+ #if ENABLED(PIDTEMP)
+ heater = H_E1;
+ break;
+ #else
+ dgus_screen_handler.SetStatusMessage(F("PID disabled"));
+ return;
+ #endif
+ #endif
+ }
+
+ char buffer[24];
+ snprintf_P(buffer, sizeof(buffer), PSTR("M303C%dE%dS%dU1"), cycles, heater, dgus_screen_handler.pid_temp);
+
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 1);
+ dgus_screen_handler.SetMessageLinePGM(PSTR("PID autotuning..."), 2);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 3);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 4);
+ dgus_screen_handler.ShowWaitScreen(DGUS_Screen::PID);
+
+ queue.enqueue_one_now(buffer);
+ queue.enqueue_now_P(DGUS_CMD_EEPROM_SAVE);
+}
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+ void DGUSRxHandler::PowerLossAbort(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Popup result = (DGUS_Data::Popup)((uint8_t*)data_ptr)[1];
+
+ if (result != DGUS_Data::Popup::CONFIRMED) {
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ dgus_screen_handler.TriggerScreenChange(DGUS_Screen::HOME);
+
+ queue.enqueue_now(F("M1000C"));
+ }
+
+ void DGUSRxHandler::PowerLossResume(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Popup result = (DGUS_Data::Popup)((uint8_t*)data_ptr)[1];
+
+ if (result != DGUS_Data::Popup::CONFIRMED) {
+ return;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return;
+ }
+
+ if (!recovery.valid()) {
+ dgus_screen_handler.SetStatusMessage(F("Invalid recovery data"));
+ return;
+ }
+
+ dgus_screen_handler.TriggerScreenChange(DGUS_Screen::PRINT_STATUS);
+
+ queue.enqueue_now(F("M1000"));
+ }
+#endif // POWER_LOSS_RECOVERY
+
+void DGUSRxHandler::WaitAbort(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ const DGUS_Data::Popup result = (DGUS_Data::Popup)((uint8_t*)data_ptr)[1];
+
+ if (result != DGUS_Data::Popup::CONFIRMED) {
+ return;
+ }
+
+ if (!ExtUI::isPrintingPaused()) {
+ dgus_screen_handler.TriggerFullUpdate();
+ return;
+ }
+
+ ExtUI::stopPrint();
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::WaitContinue(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+ UNUSED(data_ptr);
+
+ ExtUI::setUserConfirmed();
+
+ dgus_screen_handler.TriggerFullUpdate();
+}
+
+void DGUSRxHandler::FanSpeed(DGUS_VP &vp, void *data_ptr) {
+ uint8_t speed = ((uint8_t*)data_ptr)[1];
+ switch (vp.addr) {
+ default: return;
+ case DGUS_Addr::FAN0_Speed:
+ ExtUI::setTargetFan_percent(speed, ExtUI::FAN0);
+ break;
+ }
+}
+
+void DGUSRxHandler::Volume(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ uint8_t volume = ((uint8_t*)data_ptr)[1];
+ dgus_display.SetVolume(volume);
+
+ dgus_screen_handler.TriggerEEPROMSave();
+}
+
+void DGUSRxHandler::Brightness(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+
+ uint8_t brightness = ((uint8_t*)data_ptr)[1];
+ dgus_display.SetBrightness(brightness);
+
+ dgus_screen_handler.TriggerEEPROMSave();
+}
+
+void DGUSRxHandler::Debug(DGUS_VP &vp, void *data_ptr) {
+ UNUSED(vp);
+ UNUSED(data_ptr);
+
+ ++dgus_screen_handler.debug_count;
+
+ if (dgus_screen_handler.debug_count >= 10) {
+ dgus_screen_handler.TriggerScreenChange(DGUS_Screen::DEBUG);
+ }
+}
+
+void DGUSRxHandler::StringToExtra(DGUS_VP &vp, void *data_ptr) {
+ if (!vp.size || !vp.extra) return;
+ memcpy(vp.extra, data_ptr, vp.size);
+}
+
+#endif // DGUS_LCD_UI_RELOADED
diff --git a/src/lcd/extui/dgus_reloaded/DGUSRxHandler.h b/src/lcd/extui/dgus_reloaded/DGUSRxHandler.h
new file mode 100644
index 0000000..c2e6e43
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSRxHandler.h
@@ -0,0 +1,122 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+#include "DGUSDisplay.h"
+#include "definition/DGUS_VP.h"
+
+namespace DGUSRxHandler {
+
+ void ScreenChange(DGUS_VP &, void *);
+
+ #if ENABLED(SDSUPPORT)
+ void Scroll(DGUS_VP &, void *);
+ void SelectFile(DGUS_VP &, void *);
+ void PrintFile(DGUS_VP &, void *);
+ #endif
+
+ void PrintAbort(DGUS_VP &, void *);
+ void PrintPause(DGUS_VP &, void *);
+ void PrintResume(DGUS_VP &, void *);
+
+ void Feedrate(DGUS_VP &, void *);
+ void Flowrate(DGUS_VP &, void *);
+ void BabystepSet(DGUS_VP &, void *);
+ void Babystep(DGUS_VP &, void *);
+
+ void TempPreset(DGUS_VP &, void *);
+ void TempTarget(DGUS_VP &, void *);
+ void TempCool(DGUS_VP &, void *);
+
+ void Steppers(DGUS_VP &, void *);
+
+ void ZOffset(DGUS_VP &, void *);
+ void ZOffsetStep(DGUS_VP &, void *);
+ void ZOffsetSetStep(DGUS_VP &, void *);
+
+ void MoveToPoint(DGUS_VP &, void *);
+
+ void Probe(DGUS_VP &, void *);
+ void DisableABL(DGUS_VP &, void *);
+
+ void FilamentSelect(DGUS_VP &, void *);
+ void FilamentLength(DGUS_VP &, void *);
+ void FilamentMove(DGUS_VP &, void *);
+
+ void Home(DGUS_VP &, void *);
+ void Move(DGUS_VP &, void *);
+ void MoveStep(DGUS_VP &, void *);
+ void MoveSetStep(DGUS_VP &, void *);
+
+ void GcodeClear(DGUS_VP &, void *);
+ void GcodeExecute(DGUS_VP &, void *);
+
+ void ResetEEPROM(DGUS_VP &, void *);
+
+ void SettingsExtra(DGUS_VP &, void *);
+
+ void PIDSelect(DGUS_VP &, void *);
+ void PIDSetTemp(DGUS_VP &, void *);
+ void PIDRun(DGUS_VP &, void *);
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void PowerLossAbort(DGUS_VP &, void *);
+ void PowerLossResume(DGUS_VP &, void *);
+ #endif
+
+ void WaitAbort(DGUS_VP &, void *);
+ void WaitContinue(DGUS_VP &, void *);
+
+ void FanSpeed(DGUS_VP &, void *);
+
+ void Volume(DGUS_VP &, void *);
+
+ void Brightness(DGUS_VP &, void *);
+
+ void Debug(DGUS_VP &, void *);
+
+ void StringToExtra(DGUS_VP &, void *);
+
+ template
+ void IntegerToExtra(DGUS_VP &vp, void *data_ptr) {
+ if (!vp.size || !vp.extra) return;
+ switch (vp.size) {
+ default: return;
+ case 1: {
+ const uint8_t data = *(uint8_t*)data_ptr;
+ *(T*)vp.extra = (T)data;
+ break;
+ }
+ case 2: {
+ const uint16_t data = Swap16(*(uint16_t*)data_ptr);
+ *(T*)vp.extra = (T)data;
+ break;
+ }
+ case 4: {
+ const uint32_t data = dgus_display.SwapBytes(*(uint32_t*)data_ptr);
+ *(T*)vp.extra = (T)data;
+ break;
+ }
+ }
+ }
+
+}
diff --git a/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.cpp b/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.cpp
new file mode 100644
index 0000000..0b584fa
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.cpp
@@ -0,0 +1,517 @@
+/**
+ * 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 .
+ *
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_RELOADED)
+
+#include "DGUSScreenHandler.h"
+
+#include "DGUSDisplay.h"
+#include "definition/DGUS_ScreenAddrList.h"
+#include "definition/DGUS_ScreenSetup.h"
+
+#include "../../../gcode/queue.h"
+
+uint8_t DGUSScreenHandler::debug_count = 0;
+
+#if ENABLED(SDSUPPORT)
+ ExtUI::FileList DGUSScreenHandler::filelist;
+ uint16_t DGUSScreenHandler::filelist_offset = 0;
+ int16_t DGUSScreenHandler::filelist_selected = -1;
+#endif
+
+DGUS_Data::StepSize DGUSScreenHandler::offset_steps = DGUS_Data::StepSize::MMP1;
+DGUS_Data::StepSize DGUSScreenHandler::move_steps = DGUS_Data::StepSize::MM10;
+
+uint16_t DGUSScreenHandler::probing_icons[] = { 0, 0 };
+
+DGUS_Data::Extruder DGUSScreenHandler::filament_extruder = DGUS_Data::Extruder::CURRENT;
+uint16_t DGUSScreenHandler::filament_length = DGUS_DEFAULT_FILAMENT_LEN;
+
+char DGUSScreenHandler::gcode[] = "";
+
+DGUS_Data::Heater DGUSScreenHandler::pid_heater = DGUS_Data::Heater::H0;
+uint16_t DGUSScreenHandler::pid_temp = DGUS_PLA_TEMP_HOTEND;
+uint8_t DGUSScreenHandler::pid_cycles = 5;
+
+bool DGUSScreenHandler::settings_ready = false;
+bool DGUSScreenHandler::booted = false;
+
+DGUS_Screen DGUSScreenHandler::current_screen = DGUS_Screen::BOOT;
+DGUS_Screen DGUSScreenHandler::new_screen = DGUS_Screen::BOOT;
+bool DGUSScreenHandler::full_update = false;
+
+DGUS_Screen DGUSScreenHandler::wait_return_screen = DGUS_Screen::HOME;
+bool DGUSScreenHandler::wait_continue = false;
+
+bool DGUSScreenHandler::leveling_active = false;
+
+millis_t DGUSScreenHandler::status_expire = 0;
+millis_t DGUSScreenHandler::eeprom_save = 0;
+
+const char DGUS_MSG_HOMING_REQUIRED[] PROGMEM = "Homing required",
+ DGUS_MSG_BUSY[] PROGMEM = "Busy",
+ DGUS_MSG_UNDEF[] PROGMEM = "-",
+ DGUS_MSG_HOMING[] PROGMEM = "Homing...",
+ DGUS_MSG_FW_OUTDATED[] PROGMEM = "DWIN GUI/OS update required",
+ DGUS_MSG_ABL_REQUIRED[] PROGMEM = "Auto bed leveling required";
+
+const char DGUS_CMD_HOME[] PROGMEM = "G28",
+ DGUS_CMD_EEPROM_SAVE[] PROGMEM = "M500";
+
+void DGUSScreenHandler::Init() {
+ dgus_display.Init();
+
+ MoveToScreen(DGUS_Screen::BOOT, true);
+}
+
+void DGUSScreenHandler::Ready() {
+ dgus_display.PlaySound(1);
+}
+
+void DGUSScreenHandler::Loop() {
+ if (!settings_ready || current_screen == DGUS_Screen::KILL) {
+ return;
+ }
+
+ const millis_t ms = ExtUI::safe_millis();
+ static millis_t next_event_ms = 0;
+
+ if (new_screen != DGUS_Screen::BOOT) {
+ const DGUS_Screen screen = new_screen;
+ new_screen = DGUS_Screen::BOOT;
+ if (current_screen == screen)
+ TriggerFullUpdate();
+ else
+ MoveToScreen(screen);
+ return;
+ }
+
+ if (!booted && ELAPSED(ms, 3000)) {
+ booted = true;
+
+ dgus_display.ReadVersions();
+
+ if (current_screen == DGUS_Screen::BOOT)
+ MoveToScreen(DGUS_Screen::HOME);
+
+ return;
+ }
+
+ if (ELAPSED(ms, next_event_ms) || full_update) {
+ next_event_ms = ms + DGUS_UPDATE_INTERVAL_MS;
+
+ if (!SendScreenVPData(current_screen, full_update))
+ DEBUG_ECHOLNPGM("SendScreenVPData failed");
+
+ return;
+ }
+
+ if (current_screen == DGUS_Screen::WAIT
+ && ((wait_continue && !wait_for_user)
+ || (!wait_continue && IsPrinterIdle()))
+ ) {
+ MoveToScreen(wait_return_screen, true);
+ return;
+ }
+
+ if (current_screen == DGUS_Screen::LEVELING_PROBING && IsPrinterIdle()) {
+ dgus_display.PlaySound(3);
+
+ SetStatusMessage(ExtUI::getMeshValid() ? F("Probing successful") : F("Probing failed"));
+
+ MoveToScreen(DGUS_Screen::LEVELING_AUTOMATIC);
+ return;
+ }
+
+ if (status_expire > 0 && ELAPSED(ms, status_expire)) {
+ SetStatusMessage(FPSTR(NUL_STR), 0);
+ return;
+ }
+
+ if (eeprom_save > 0 && ELAPSED(ms, eeprom_save) && IsPrinterIdle()) {
+ eeprom_save = 0;
+ queue.enqueue_now_P(DGUS_CMD_EEPROM_SAVE);
+ return;
+ }
+
+ dgus_display.Loop();
+}
+
+void DGUSScreenHandler::PrinterKilled(FSTR_P const error, FSTR_P const component) {
+ SetMessageLinePGM(FTOP(error), 1);
+ SetMessageLinePGM(FTOP(component), 2);
+ SetMessageLinePGM(NUL_STR, 3);
+ SetMessageLinePGM(GET_TEXT(MSG_PLEASE_RESET), 4);
+
+ dgus_display.PlaySound(3, 1, 200);
+
+ MoveToScreen(DGUS_Screen::KILL, true);
+}
+
+void DGUSScreenHandler::UserConfirmRequired(const char * const msg) {
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 1);
+ dgus_screen_handler.SetMessageLine(msg, 2);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 3);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 4);
+
+ dgus_display.PlaySound(3);
+
+ dgus_screen_handler.ShowWaitScreen(current_screen, true);
+}
+
+void DGUSScreenHandler::SettingsReset() {
+ dgus_display.SetVolume(DGUS_DEFAULT_VOLUME);
+ dgus_display.SetBrightness(DGUS_DEFAULT_BRIGHTNESS);
+
+ if (!settings_ready) {
+ settings_ready = true;
+ Ready();
+ }
+
+ SetStatusMessage(F("EEPROM reset"));
+}
+
+void DGUSScreenHandler::StoreSettings(char *buff) {
+ eeprom_data_t data;
+
+ static_assert(sizeof(data) <= ExtUI::eeprom_data_size, "sizeof(eeprom_data_t) > eeprom_data_size.");
+
+ data.initialized = true;
+ data.volume = dgus_display.GetVolume();
+ data.brightness = dgus_display.GetBrightness();
+ data.abl_okay = (ExtUI::getLevelingActive() && ExtUI::getMeshValid());
+
+ memcpy(buff, &data, sizeof(data));
+}
+
+void DGUSScreenHandler::LoadSettings(const char *buff) {
+ eeprom_data_t data;
+
+ static_assert(sizeof(data) <= ExtUI::eeprom_data_size, "sizeof(eeprom_data_t) > eeprom_data_size.");
+
+ memcpy(&data, buff, sizeof(data));
+
+ dgus_display.SetVolume(data.initialized ? data.volume : DGUS_DEFAULT_VOLUME);
+ dgus_display.SetBrightness(data.initialized ? data.brightness : DGUS_DEFAULT_BRIGHTNESS);
+
+ if (data.initialized) {
+ leveling_active = (data.abl_okay && ExtUI::getMeshValid());
+ ExtUI::setLevelingActive(leveling_active);
+ }
+}
+
+void DGUSScreenHandler::ConfigurationStoreWritten(bool success) {
+ if (!success)
+ SetStatusMessage(F("EEPROM write failed"));
+}
+
+void DGUSScreenHandler::ConfigurationStoreRead(bool success) {
+ if (!success) {
+ SetStatusMessage(F("EEPROM read failed"));
+ }
+ else if (!settings_ready) {
+ settings_ready = true;
+ Ready();
+ }
+}
+
+void DGUSScreenHandler::PlayTone(const uint16_t frequency, const uint16_t duration) {
+ UNUSED(duration);
+
+ if (frequency >= 1 && frequency <= 255) {
+ if (duration >= 1 && duration <= 255)
+ dgus_display.PlaySound((uint8_t)frequency, (uint8_t)duration);
+ else
+ dgus_display.PlaySound((uint8_t)frequency);
+ }
+}
+
+void DGUSScreenHandler::MeshUpdate(const int8_t xpos, const int8_t ypos) {
+ if (current_screen != DGUS_Screen::LEVELING_PROBING) {
+ if (current_screen == DGUS_Screen::LEVELING_AUTOMATIC)
+ TriggerFullUpdate();
+ return;
+ }
+
+ uint8_t point = ypos * GRID_MAX_POINTS_X + xpos;
+ probing_icons[point < 16 ? 0 : 1] |= (1U << (point % 16));
+
+ if (xpos >= GRID_MAX_POINTS_X - 1 && ypos >= GRID_MAX_POINTS_Y - 1 && !ExtUI::getMeshValid())
+ probing_icons[0] = probing_icons[1] = 0;
+
+ TriggerFullUpdate();
+}
+
+void DGUSScreenHandler::PrintTimerStarted() {
+ TriggerScreenChange(DGUS_Screen::PRINT_STATUS);
+}
+
+void DGUSScreenHandler::PrintTimerPaused() {
+ dgus_display.PlaySound(3);
+ TriggerFullUpdate();
+}
+
+void DGUSScreenHandler::PrintTimerStopped() {
+ if (current_screen != DGUS_Screen::PRINT_STATUS && current_screen != DGUS_Screen::PRINT_ADJUST)
+ return;
+
+ dgus_display.PlaySound(3);
+
+ TriggerScreenChange(DGUS_Screen::PRINT_FINISHED);
+}
+
+void DGUSScreenHandler::FilamentRunout(const ExtUI::extruder_t extruder) {
+ char buffer[21];
+ snprintf_P(buffer, sizeof(buffer), PSTR("Filament runout E%d"), extruder);
+
+ SetStatusMessage(buffer);
+
+ dgus_display.PlaySound(3);
+}
+
+#if ENABLED(SDSUPPORT)
+
+ void DGUSScreenHandler::SDCardInserted() {
+ if (current_screen == DGUS_Screen::HOME)
+ TriggerScreenChange(DGUS_Screen::PRINT);
+ }
+
+ void DGUSScreenHandler::SDCardRemoved() {
+ if (current_screen == DGUS_Screen::PRINT)
+ TriggerScreenChange(DGUS_Screen::HOME);
+ }
+
+ void DGUSScreenHandler::SDCardError() {
+ SetStatusMessage(GET_TEXT_F(MSG_MEDIA_READ_ERROR));
+ if (current_screen == DGUS_Screen::PRINT)
+ TriggerScreenChange(DGUS_Screen::HOME);
+ }
+
+#endif // SDSUPPORT
+
+#if ENABLED(POWER_LOSS_RECOVERY)
+
+ void DGUSScreenHandler::PowerLossResume() {
+ MoveToScreen(DGUS_Screen::POWERLOSS, true);
+ }
+
+#endif // POWER_LOSS_RECOVERY
+
+#if HAS_PID_HEATING
+
+ void DGUSScreenHandler::PidTuning(const ExtUI::result_t rst) {
+ switch (rst) {
+ case ExtUI::PID_STARTED:
+ SetStatusMessage(GET_TEXT_F(MSG_PID_AUTOTUNE));
+ break;
+ case ExtUI::PID_BAD_EXTRUDER_NUM:
+ SetStatusMessage(GET_TEXT_F(MSG_PID_BAD_EXTRUDER_NUM));
+ break;
+ case ExtUI::PID_TEMP_TOO_HIGH:
+ SetStatusMessage(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH));
+ break;
+ case ExtUI::PID_TUNING_TIMEOUT:
+ SetStatusMessage(GET_TEXT_F(MSG_PID_TIMEOUT));
+ break;
+ case ExtUI::PID_DONE:
+ SetStatusMessage(GET_TEXT_F(MSG_PID_AUTOTUNE_DONE));
+ break;
+ default:
+ return;
+ }
+
+ dgus_display.PlaySound(3);
+ }
+
+#endif // HAS_PID_HEATING
+
+void DGUSScreenHandler::SetMessageLine(const char* msg, uint8_t line) {
+ switch (line) {
+ default: return;
+ case 1:
+ dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Line1, msg, DGUS_LINE_LEN, true, true);
+ break;
+ case 2:
+ dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Line2, msg, DGUS_LINE_LEN, true, true);
+ break;
+ case 3:
+ dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Line3, msg, DGUS_LINE_LEN, true, true);
+ break;
+ case 4:
+ dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Line4, msg, DGUS_LINE_LEN, true, true);
+ break;
+ }
+}
+
+void DGUSScreenHandler::SetMessageLinePGM(PGM_P msg, uint8_t line) {
+ switch (line) {
+ default: return;
+ case 1:
+ dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Line1, msg, DGUS_LINE_LEN, true, true);
+ break;
+ case 2:
+ dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Line2, msg, DGUS_LINE_LEN, true, true);
+ break;
+ case 3:
+ dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Line3, msg, DGUS_LINE_LEN, true, true);
+ break;
+ case 4:
+ dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Line4, msg, DGUS_LINE_LEN, true, true);
+ break;
+ }
+}
+
+void DGUSScreenHandler::SetStatusMessage(const char* msg, const millis_t duration) {
+ dgus_display.WriteString((uint16_t)DGUS_Addr::MESSAGE_Status, msg, DGUS_STATUS_LEN, false, true);
+
+ status_expire = (duration > 0 ? ExtUI::safe_millis() + duration : 0);
+}
+
+void DGUSScreenHandler::SetStatusMessage(FSTR_P const fmsg, const millis_t duration) {
+ dgus_display.WriteStringPGM((uint16_t)DGUS_Addr::MESSAGE_Status, FTOP(fmsg), DGUS_STATUS_LEN, false, true);
+
+ status_expire = (duration > 0 ? ExtUI::safe_millis() + duration : 0);
+}
+
+void DGUSScreenHandler::ShowWaitScreen(DGUS_Screen return_screen, bool has_continue) {
+ if (return_screen != DGUS_Screen::WAIT) {
+ wait_return_screen = return_screen;
+ }
+ wait_continue = has_continue;
+
+ TriggerScreenChange(DGUS_Screen::WAIT);
+}
+
+DGUS_Screen DGUSScreenHandler::GetCurrentScreen() {
+ return current_screen;
+}
+
+void DGUSScreenHandler::TriggerScreenChange(DGUS_Screen screen) {
+ new_screen = screen;
+}
+
+void DGUSScreenHandler::TriggerFullUpdate() {
+ full_update = true;
+}
+
+void DGUSScreenHandler::TriggerEEPROMSave() {
+ eeprom_save = ExtUI::safe_millis() + 500;
+}
+
+bool DGUSScreenHandler::IsPrinterIdle() {
+ return (!ExtUI::commandsInQueue()
+ && !ExtUI::isMoving());
+}
+
+const DGUS_Addr* DGUSScreenHandler::FindScreenAddrList(DGUS_Screen screen) {
+ DGUS_ScreenAddrList list;
+ const DGUS_ScreenAddrList *map = screen_addr_list_map;
+
+ do {
+ memcpy_P(&list, map, sizeof(*map));
+ if (!list.addr_list) break;
+ if (list.screen == screen) {
+ return list.addr_list;
+ }
+ } while (++map);
+
+ return nullptr;
+}
+
+bool DGUSScreenHandler::CallScreenSetup(DGUS_Screen screen) {
+ DGUS_ScreenSetup setup;
+ const DGUS_ScreenSetup *list = screen_setup_list;
+
+ do {
+ memcpy_P(&setup, list, sizeof(*list));
+ if (!setup.setup_fn) break;
+ if (setup.screen == screen) {
+ return setup.setup_fn();
+ }
+ } while (++list);
+
+ return true;
+}
+
+void DGUSScreenHandler::MoveToScreen(DGUS_Screen screen, bool abort_wait) {
+ if (current_screen == DGUS_Screen::KILL) {
+ return;
+ }
+
+ if (current_screen == DGUS_Screen::WAIT) {
+ if (screen != DGUS_Screen::WAIT) {
+ wait_return_screen = screen;
+ }
+
+ if (!abort_wait) return;
+
+ if (wait_continue && wait_for_user) {
+ ExtUI::setUserConfirmed();
+ }
+ }
+
+ if (!CallScreenSetup(screen)) return;
+
+ if (!SendScreenVPData(screen, true)) {
+ DEBUG_ECHOLNPGM("SendScreenVPData failed");
+ return;
+ }
+
+ current_screen = screen;
+ dgus_display.SwitchScreen(current_screen);
+}
+
+bool DGUSScreenHandler::SendScreenVPData(DGUS_Screen screen, bool complete_update) {
+ if (complete_update) {
+ full_update = false;
+ }
+
+ const DGUS_Addr *list = FindScreenAddrList(screen);
+
+ while (true) {
+ if (!list) return true; // Nothing left to send
+
+ const uint16_t addr = pgm_read_word(list++);
+ if (!addr) return true; // Nothing left to send
+
+ DGUS_VP vp;
+ if (!DGUS_PopulateVP((DGUS_Addr)addr, &vp)) continue; // Invalid VP
+ if (!vp.tx_handler) continue; // Nothing to send
+ if (!complete_update && !(vp.flags & VPFLAG_AUTOUPLOAD)) continue; // Unnecessary VP
+
+ uint8_t expected_tx = 6 + vp.size; // 6 bytes header + payload.
+ const millis_t try_until = ExtUI::safe_millis() + 1000;
+
+ while (expected_tx > dgus_display.GetFreeTxBuffer()) {
+ if (ELAPSED(ExtUI::safe_millis(), try_until)) return false; // Stop trying after 1 second
+
+ dgus_display.FlushTx(); // Flush the TX buffer
+ delay(50);
+ }
+
+ vp.tx_handler(vp);
+ }
+}
+
+#endif // DGUS_LCD_UI_RELOADED
diff --git a/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.h b/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.h
new file mode 100644
index 0000000..cc59bda
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSScreenHandler.h
@@ -0,0 +1,151 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+#include "config/DGUS_Addr.h"
+#include "config/DGUS_Data.h"
+#include "config/DGUS_Screen.h"
+#include "config/DGUS_Constants.h"
+
+#include "../ui_api.h"
+#include "../../../inc/MarlinConfigPre.h"
+
+class DGUSScreenHandler {
+public:
+ DGUSScreenHandler() = default;
+
+ static void Init();
+ static void Ready();
+ static void Loop();
+
+ static void PrinterKilled(FSTR_P const error, FSTR_P const component);
+ static void UserConfirmRequired(const char * const msg);
+ static void SettingsReset();
+ static void StoreSettings(char *buff);
+ static void LoadSettings(const char *buff);
+ static void ConfigurationStoreWritten(bool success);
+ static void ConfigurationStoreRead(bool success);
+
+ static void PlayTone(const uint16_t frequency, const uint16_t duration);
+ static void MeshUpdate(const int8_t xpos, const int8_t ypos);
+ static void PrintTimerStarted();
+ static void PrintTimerPaused();
+ static void PrintTimerStopped();
+ static void FilamentRunout(const ExtUI::extruder_t extruder);
+
+ #if ENABLED(SDSUPPORT)
+ /// Marlin informed us that a new SD has been inserted.
+ static void SDCardInserted();
+ /// Marlin informed us that the SD Card has been removed().
+ static void SDCardRemoved();
+ /// Marlin informed us about a bad SD Card.
+ static void SDCardError();
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ static void PowerLossResume();
+ #endif
+
+ #if HAS_PID_HEATING
+ static void PidTuning(const ExtUI::result_t rst);
+ #endif
+
+ static void SetMessageLine(const char* msg, uint8_t line);
+ static void SetMessageLinePGM(PGM_P msg, uint8_t line);
+
+ static void SetStatusMessage(const char* msg, const millis_t duration = DGUS_STATUS_EXPIRATION_MS);
+ static void SetStatusMessage(FSTR_P const msg, const millis_t duration = DGUS_STATUS_EXPIRATION_MS);
+
+ static void ShowWaitScreen(DGUS_Screen return_screen, bool has_continue = false);
+
+ static DGUS_Screen GetCurrentScreen();
+ static void TriggerScreenChange(DGUS_Screen screen);
+ static void TriggerFullUpdate();
+
+ static void TriggerEEPROMSave();
+
+ static bool IsPrinterIdle();
+
+ static uint8_t debug_count;
+
+ #if ENABLED(SDSUPPORT)
+ static ExtUI::FileList filelist;
+ static uint16_t filelist_offset;
+ static int16_t filelist_selected;
+ #endif
+
+ static DGUS_Data::StepSize offset_steps;
+ static DGUS_Data::StepSize move_steps;
+
+ static uint16_t probing_icons[2];
+
+ static DGUS_Data::Extruder filament_extruder;
+ static uint16_t filament_length;
+
+ static char gcode[DGUS_GCODE_LEN + 1];
+
+ static DGUS_Data::Heater pid_heater;
+ static uint16_t pid_temp;
+ static uint8_t pid_cycles;
+
+ static bool wait_continue;
+
+ static bool leveling_active;
+
+private:
+ static const DGUS_Addr* FindScreenAddrList(DGUS_Screen screen);
+ static bool CallScreenSetup(DGUS_Screen screen);
+
+ static void MoveToScreen(DGUS_Screen screen, bool abort_wait = false);
+ static bool SendScreenVPData(DGUS_Screen screen, bool complete_update);
+
+ static bool settings_ready;
+ static bool booted;
+
+ static DGUS_Screen current_screen;
+ static DGUS_Screen new_screen;
+ static bool full_update;
+
+ static DGUS_Screen wait_return_screen;
+
+ static millis_t status_expire;
+ static millis_t eeprom_save;
+
+ typedef struct {
+ bool initialized;
+ uint8_t volume;
+ uint8_t brightness;
+ bool abl_okay;
+ } eeprom_data_t;
+};
+
+extern DGUSScreenHandler dgus_screen_handler;
+
+extern const char DGUS_MSG_HOMING_REQUIRED[],
+ DGUS_MSG_BUSY[],
+ DGUS_MSG_UNDEF[],
+ DGUS_MSG_HOMING[],
+ DGUS_MSG_FW_OUTDATED[],
+ DGUS_MSG_ABL_REQUIRED[];
+
+extern const char DGUS_CMD_HOME[],
+ DGUS_CMD_EEPROM_SAVE[];
diff --git a/src/lcd/extui/dgus_reloaded/DGUSSetupHandler.cpp b/src/lcd/extui/dgus_reloaded/DGUSSetupHandler.cpp
new file mode 100644
index 0000000..090d53c
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSSetupHandler.cpp
@@ -0,0 +1,209 @@
+/**
+ * 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 .
+ *
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_RELOADED)
+
+#include "DGUSSetupHandler.h"
+
+#include "DGUSDisplay.h"
+#include "DGUSScreenHandler.h"
+
+#include "../../../gcode/queue.h"
+
+#if ENABLED(SDSUPPORT)
+ bool DGUSSetupHandler::Print() {
+ dgus_screen_handler.filelist.refresh();
+
+ while (!dgus_screen_handler.filelist.isAtRootDir()) {
+ dgus_screen_handler.filelist.upDir();
+ }
+
+ dgus_screen_handler.filelist_offset = 0;
+ dgus_screen_handler.filelist_selected = -1;
+
+ return true;
+ }
+#endif
+
+bool DGUSSetupHandler::PrintStatus() {
+ if (ExtUI::isPrinting() || ExtUI::isPrintingPaused()) {
+ return true;
+ }
+
+ dgus_screen_handler.TriggerScreenChange(DGUS_Screen::PRINT_FINISHED);
+ return false;
+}
+
+bool DGUSSetupHandler::PrintAdjust() {
+ if (ExtUI::isPrinting() || ExtUI::isPrintingPaused()) {
+ return true;
+ }
+
+ dgus_screen_handler.TriggerScreenChange(DGUS_Screen::PRINT_FINISHED);
+ return false;
+}
+
+bool DGUSSetupHandler::LevelingMenu() {
+ ExtUI::setLevelingActive(dgus_screen_handler.leveling_active);
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return false;
+ }
+
+ if (ExtUI::isPositionKnown()) {
+ if (ExtUI::getAxisPosition_mm(ExtUI::Z) < 10.0f) {
+ queue.enqueue_now(F("G0Z10"));
+ }
+
+ return true;
+ }
+
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 1);
+ dgus_screen_handler.SetMessageLinePGM(DGUS_MSG_HOMING, 2);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 3);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 4);
+ dgus_screen_handler.ShowWaitScreen(DGUS_Screen::LEVELING_MENU);
+
+ queue.enqueue_now_P(DGUS_CMD_HOME);
+
+ return false;
+}
+
+bool DGUSSetupHandler::LevelingManual() {
+ ExtUI::setLevelingActive(false);
+
+ if (ExtUI::isPositionKnown()) {
+ return true;
+ }
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return false;
+ }
+
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 1);
+ dgus_screen_handler.SetMessageLinePGM(DGUS_MSG_HOMING, 2);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 3);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 4);
+ dgus_screen_handler.ShowWaitScreen(DGUS_Screen::LEVELING_MANUAL);
+
+ queue.enqueue_now_P(DGUS_CMD_HOME);
+
+ return false;
+}
+
+bool DGUSSetupHandler::LevelingOffset() {
+ dgus_screen_handler.offset_steps = DGUS_Data::StepSize::MMP1;
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return false;
+ }
+
+ if (ExtUI::isPositionKnown()) {
+ if (ExtUI::getAxisPosition_mm(ExtUI::Z) < 4.0f) {
+ queue.enqueue_now(F("G0Z4"));
+ }
+
+ char buffer[20];
+ snprintf_P(buffer, sizeof(buffer), PSTR("G0X%dY%d"), DGUS_LEVEL_CENTER_X, DGUS_LEVEL_CENTER_Y);
+
+ queue.enqueue_one_now(buffer);
+ queue.enqueue_now(F("G0Z0"));
+
+ return true;
+ }
+
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 1);
+ dgus_screen_handler.SetMessageLinePGM(DGUS_MSG_HOMING, 2);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 3);
+ dgus_screen_handler.SetMessageLinePGM(NUL_STR, 4);
+ dgus_screen_handler.ShowWaitScreen(DGUS_Screen::LEVELING_OFFSET);
+
+ queue.enqueue_now_P(DGUS_CMD_HOME);
+
+ return false;
+}
+
+bool DGUSSetupHandler::LevelingAutomatic() {
+ if (ExtUI::getMeshValid()) {
+ dgus_screen_handler.leveling_active = true;
+
+ ExtUI::setLevelingActive(true);
+ }
+
+ return true;
+}
+
+bool DGUSSetupHandler::LevelingProbing() {
+ dgus_screen_handler.probing_icons[0] = 0;
+ dgus_screen_handler.probing_icons[1] = 0;
+
+ return true;
+}
+
+bool DGUSSetupHandler::Filament() {
+ dgus_screen_handler.filament_extruder = DGUS_Data::Extruder::CURRENT;
+ dgus_screen_handler.filament_length = DGUS_DEFAULT_FILAMENT_LEN;
+
+ return true;
+}
+
+bool DGUSSetupHandler::Move() {
+ dgus_screen_handler.move_steps = DGUS_Data::StepSize::MM10;
+
+ if (!dgus_screen_handler.IsPrinterIdle()) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_BUSY));
+ return false;
+ }
+
+ return true;
+}
+
+bool DGUSSetupHandler::Gcode() {
+ ZERO(dgus_screen_handler.gcode);
+
+ if (dgus_display.gui_version < 0x30 || dgus_display.os_version < 0x21) {
+ dgus_screen_handler.SetStatusMessage(FPSTR(DGUS_MSG_FW_OUTDATED));
+ return false;
+ }
+
+ return true;
+}
+
+bool DGUSSetupHandler::PID() {
+ dgus_screen_handler.pid_heater = DGUS_Data::Heater::H0;
+ dgus_screen_handler.pid_temp = DGUS_PLA_TEMP_HOTEND;
+
+ return true;
+}
+
+bool DGUSSetupHandler::Infos() {
+ dgus_screen_handler.debug_count = 0;
+
+ return true;
+}
+
+#endif // DGUS_LCD_UI_RELOADED
diff --git a/src/lcd/extui/dgus_reloaded/DGUSSetupHandler.h b/src/lcd/extui/dgus_reloaded/DGUSSetupHandler.h
new file mode 100644
index 0000000..9e38664
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSSetupHandler.h
@@ -0,0 +1,42 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+namespace DGUSSetupHandler {
+
+ #if ENABLED(SDSUPPORT)
+ bool Print();
+ #endif
+ bool PrintStatus();
+ bool PrintAdjust();
+ bool LevelingMenu();
+ bool LevelingOffset();
+ bool LevelingManual();
+ bool LevelingAutomatic();
+ bool LevelingProbing();
+ bool Filament();
+ bool Move();
+ bool Gcode();
+ bool PID();
+ bool Infos();
+
+}
diff --git a/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp b/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp
new file mode 100644
index 0000000..62df84e
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSTxHandler.cpp
@@ -0,0 +1,618 @@
+/**
+ * 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 .
+ *
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_RELOADED)
+
+#include "DGUSTxHandler.h"
+
+#include "DGUSScreenHandler.h"
+#include "config/DGUS_Data.h"
+
+#include "../ui_api.h"
+#include "../../../module/stepper.h"
+#include "../../../module/printcounter.h"
+#if ENABLED(ADVANCED_PAUSE_FEATURE)
+ #include "../../../feature/pause.h"
+#endif
+
+#if ENABLED(SDSUPPORT)
+ void DGUSTxHandler::SetFileControlState(int file, bool state) {
+ DGUS_Control control;
+
+ switch (file) {
+ default: return;
+ case 0:
+ control = DGUS_Control::FILE0;
+ break;
+ case 1:
+ control = DGUS_Control::FILE1;
+ break;
+ case 2:
+ control = DGUS_Control::FILE2;
+ break;
+ case 3:
+ control = DGUS_Control::FILE3;
+ break;
+ case 4:
+ control = DGUS_Control::FILE4;
+ break;
+ }
+
+ if (state) {
+ dgus_display.EnableControl(DGUS_Screen::PRINT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ control);
+ }
+ else {
+ dgus_display.DisableControl(DGUS_Screen::PRINT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ control);
+ }
+ }
+
+ void DGUSTxHandler::FileType(DGUS_VP &vp) {
+ // Batch send
+ uint16_t data[DGUS_FILE_COUNT];
+
+ for (int i = 0; i < DGUS_FILE_COUNT; i++) {
+ if (!dgus_screen_handler.filelist.seek(dgus_screen_handler.filelist_offset + i)) {
+ data[i] = Swap16((uint16_t)DGUS_Data::SDType::NONE);
+
+ SetFileControlState(i, false);
+ continue;
+ }
+
+ data[i] = dgus_screen_handler.filelist.isDir() ?
+ Swap16((uint16_t)DGUS_Data::SDType::DIRECTORY)
+ : Swap16((uint16_t)DGUS_Data::SDType::FILE);
+
+ SetFileControlState(i, true);
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, data, sizeof(*data) * DGUS_FILE_COUNT);
+ }
+
+ void DGUSTxHandler::FileName(DGUS_VP &vp) {
+ uint8_t offset;
+
+ switch (vp.addr) {
+ default: return;
+ case DGUS_Addr::SD_FileName0:
+ offset = 0;
+ break;
+ case DGUS_Addr::SD_FileName1:
+ offset = 1;
+ break;
+ case DGUS_Addr::SD_FileName2:
+ offset = 2;
+ break;
+ case DGUS_Addr::SD_FileName3:
+ offset = 3;
+ break;
+ case DGUS_Addr::SD_FileName4:
+ offset = 4;
+ break;
+ }
+
+ if (dgus_screen_handler.filelist.seek(dgus_screen_handler.filelist_offset + offset)) {
+ dgus_display.WriteString((uint16_t)vp.addr, dgus_screen_handler.filelist.filename(), vp.size);
+ }
+ else {
+ dgus_display.WriteStringPGM((uint16_t)vp.addr, NUL_STR, vp.size);
+ }
+ }
+
+ void DGUSTxHandler::ScrollIcons(DGUS_VP &vp) {
+ uint16_t icons = 0;
+
+ if (!dgus_screen_handler.filelist.isAtRootDir()) {
+ icons |= (uint16_t)DGUS_Data::ScrollIcon::GO_BACK;
+
+ dgus_display.EnableControl(DGUS_Screen::PRINT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::GO_BACK);
+ }
+ else {
+ dgus_display.DisableControl(DGUS_Screen::PRINT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::GO_BACK);
+ }
+
+ if (dgus_screen_handler.filelist_offset > 0) {
+ icons |= (uint16_t)DGUS_Data::ScrollIcon::UP;
+
+ dgus_display.EnableControl(DGUS_Screen::PRINT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::SCROLL_UP);
+ }
+ else {
+ dgus_display.DisableControl(DGUS_Screen::PRINT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::SCROLL_UP);
+ }
+
+ if (dgus_screen_handler.filelist_offset + DGUS_FILE_COUNT < dgus_screen_handler.filelist.count()) {
+ icons |= (uint16_t)DGUS_Data::ScrollIcon::DOWN;
+
+ dgus_display.EnableControl(DGUS_Screen::PRINT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::SCROLL_DOWN);
+ }
+ else {
+ dgus_display.DisableControl(DGUS_Screen::PRINT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::SCROLL_DOWN);
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(icons));
+ }
+
+ void DGUSTxHandler::SelectedFileName(DGUS_VP &vp) {
+ if (dgus_screen_handler.filelist_selected < 0
+ || !dgus_screen_handler.filelist.seek(dgus_screen_handler.filelist_selected)) {
+ dgus_display.WriteStringPGM((uint16_t)vp.addr, NUL_STR, vp.size);
+ return;
+ }
+
+ dgus_display.WriteString((uint16_t)vp.addr, dgus_screen_handler.filelist.filename(), vp.size);
+ }
+#endif // SDSUPPORT
+
+void DGUSTxHandler::PositionZ(DGUS_VP &vp) {
+ float position = ExtUI::isAxisPositionKnown(ExtUI::Z) ?
+ planner.get_axis_position_mm(Z_AXIS)
+ : 0;
+
+ const int16_t data = dgus_display.ToFixedPoint(position);
+ dgus_display.Write((uint16_t)vp.addr, Swap16(data));
+}
+
+void DGUSTxHandler::Ellapsed(DGUS_VP &vp) {
+ char buffer[21];
+ duration_t(print_job_timer.duration()).toString(buffer);
+
+ dgus_display.WriteString((uint16_t)vp.addr, buffer, vp.size);
+}
+
+void DGUSTxHandler::Percent(DGUS_VP &vp) {
+ uint16_t progress;
+
+ switch (vp.addr) {
+ default: return;
+ case DGUS_Addr::STATUS_Percent:
+ progress = constrain(ExtUI::getProgress_percent(), 0, 100);
+ break;
+ case DGUS_Addr::STATUS_Percent_Complete:
+ progress = 100;
+ break;
+ }
+
+ dgus_display.Write((uint16_t)DGUS_Addr::STATUS_Percent, Swap16(progress));
+}
+
+void DGUSTxHandler::StatusIcons(DGUS_VP &vp) {
+ uint16_t icons = 0;
+
+ if (ExtUI::isPrinting()) {
+ icons |= (uint16_t)DGUS_Data::StatusIcon::PAUSE;
+
+ dgus_display.EnableControl(DGUS_Screen::PRINT_STATUS,
+ DGUSDisplay::POPUP_WINDOW,
+ DGUS_Control::PAUSE);
+ }
+ else {
+ dgus_display.DisableControl(DGUS_Screen::PRINT_STATUS,
+ DGUSDisplay::POPUP_WINDOW,
+ DGUS_Control::PAUSE);
+ }
+
+ if (ExtUI::isPrintingPaused()) {
+ icons |= (uint16_t)DGUS_Data::StatusIcon::RESUME;
+
+ dgus_display.EnableControl(DGUS_Screen::PRINT_STATUS,
+ DGUSDisplay::POPUP_WINDOW,
+ DGUS_Control::RESUME);
+ }
+ else {
+ dgus_display.DisableControl(DGUS_Screen::PRINT_STATUS,
+ DGUSDisplay::POPUP_WINDOW,
+ DGUS_Control::RESUME);
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(icons));
+}
+
+void DGUSTxHandler::Flowrate(DGUS_VP &vp) {
+ int16_t flowrate;
+
+ switch (vp.addr) {
+ default: return;
+ case DGUS_Addr::ADJUST_Flowrate_CUR:
+ flowrate = ExtUI::getFlow_percent(TERN(HAS_MULTI_EXTRUDER, ExtUI::getActiveTool(), ExtUI::E0));
+ break;
+ #if HAS_MULTI_EXTRUDER
+ case DGUS_Addr::ADJUST_Flowrate_E0:
+ flowrate = ExtUI::getFlow_percent(ExtUI::E0);
+ break;
+ case DGUS_Addr::ADJUST_Flowrate_E1:
+ flowrate = ExtUI::getFlow_percent(ExtUI::E1);
+ break;
+ #endif
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(flowrate));
+}
+
+void DGUSTxHandler::TempMax(DGUS_VP &vp) {
+ uint16_t temp;
+
+ switch (vp.addr) {
+ default: return;
+ case DGUS_Addr::TEMP_Max_Bed:
+ temp = BED_MAX_TARGET;
+ break;
+ case DGUS_Addr::TEMP_Max_H0:
+ temp = HEATER_0_MAXTEMP - HOTEND_OVERSHOOT;
+ break;
+ #if HAS_MULTI_HOTEND
+ case DGUS_Addr::TEMP_Max_H1:
+ temp = HEATER_1_MAXTEMP - HOTEND_OVERSHOOT;
+ break;
+ #endif
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(temp));
+}
+
+void DGUSTxHandler::StepperStatus(DGUS_VP &vp) {
+ const bool motor_on = stepper.axis_enabled.bits & (_BV(NUM_AXES) - 1);
+ dgus_display.Write((uint16_t)vp.addr, Swap16(uint16_t(motor_on ? DGUS_Data::Status::ENABLED : DGUS_Data::Status::DISABLED)));
+}
+
+void DGUSTxHandler::StepIcons(DGUS_VP &vp) {
+ if (!vp.extra) return;
+ uint16_t icons = 0;
+ DGUS_Data::StepSize size = *(DGUS_Data::StepSize*)vp.extra;
+
+ switch (size) {
+ case DGUS_Data::StepSize::MM10:
+ icons |= (uint16_t)DGUS_Data::StepIcon::MM10;
+ break;
+ case DGUS_Data::StepSize::MM1:
+ icons |= (uint16_t)DGUS_Data::StepIcon::MM1;
+ break;
+ case DGUS_Data::StepSize::MMP1:
+ icons |= (uint16_t)DGUS_Data::StepIcon::MMP1;
+ break;
+ case DGUS_Data::StepSize::MMP01:
+ icons |= (uint16_t)DGUS_Data::StepIcon::MMP01;
+ break;
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(icons));
+}
+
+void DGUSTxHandler::ABLDisableIcon(DGUS_VP &vp) {
+ uint16_t data;
+
+ if (ExtUI::getLevelingActive()) {
+ data = (uint16_t)DGUS_Data::Status::ENABLED;
+
+ dgus_display.EnableControl(DGUS_Screen::LEVELING_AUTOMATIC,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::DISABLE);
+ }
+ else {
+ data = (uint16_t)DGUS_Data::Status::DISABLED;
+
+ dgus_display.DisableControl(DGUS_Screen::LEVELING_AUTOMATIC,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::DISABLE);
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(data));
+}
+
+void DGUSTxHandler::ABLGrid(DGUS_VP &vp) {
+ // Batch send
+ int16_t data[DGUS_LEVEL_GRID_SIZE];
+ xy_uint8_t point;
+ int16_t fixed;
+
+ for (int i = 0; i < DGUS_LEVEL_GRID_SIZE; i++) {
+ point.x = i % (GRID_MAX_POINTS_X);
+ point.y = i / (GRID_MAX_POINTS_X);
+ fixed = dgus_display.ToFixedPoint(ExtUI::getMeshPoint(point));
+ data[i] = Swap16(fixed);
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, data, sizeof(*data) * DGUS_LEVEL_GRID_SIZE);
+}
+
+void DGUSTxHandler::FilamentIcons(DGUS_VP &vp) {
+ uint16_t icons = 0;
+
+ switch (dgus_screen_handler.filament_extruder) {
+ default: return;
+ case DGUS_Data::Extruder::CURRENT:
+ #if HAS_MULTI_EXTRUDER
+ switch (ExtUI::getActiveTool()) {
+ default: break;
+ case ExtUI::E0:
+ icons |= (uint16_t)DGUS_Data::ExtruderIcon::E0;
+ break;
+ case ExtUI::E1:
+ icons |= (uint16_t)DGUS_Data::ExtruderIcon::E1;
+ break;
+ }
+ break;
+ #endif
+ case DGUS_Data::Extruder::E0:
+ icons |= (uint16_t)DGUS_Data::ExtruderIcon::E0;
+ break;
+ case DGUS_Data::Extruder::E1:
+ icons |= (uint16_t)DGUS_Data::ExtruderIcon::E1;
+ break;
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(icons));
+}
+
+void DGUSTxHandler::BLTouch(DGUS_VP &vp) {
+ #if ENABLED(BLTOUCH)
+ dgus_display.EnableControl(DGUS_Screen::SETTINGS_MENU2,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::EXTRA2);
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16((uint16_t)DGUS_Data::Status::ENABLED));
+ #else
+ dgus_display.DisableControl(DGUS_Screen::SETTINGS_MENU2,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::EXTRA2);
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16((uint16_t)DGUS_Data::Status::DISABLED));
+ #endif
+}
+
+void DGUSTxHandler::PIDIcons(DGUS_VP &vp) {
+ uint16_t icons = 0;
+
+ switch (dgus_screen_handler.pid_heater) {
+ default: return;
+ case DGUS_Data::Heater::BED:
+ icons |= (uint16_t)DGUS_Data::HeaterIcon::BED;
+ break;
+ case DGUS_Data::Heater::H0:
+ icons |= (uint16_t)DGUS_Data::HeaterIcon::H0;
+ break;
+ case DGUS_Data::Heater::H1:
+ icons |= (uint16_t)DGUS_Data::HeaterIcon::H1;
+ break;
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(icons));
+}
+
+void DGUSTxHandler::PIDKp(DGUS_VP &vp) {
+ float value;
+
+ switch (dgus_screen_handler.pid_heater) {
+ default: return;
+ #if ENABLED(PIDTEMPBED)
+ case DGUS_Data::Heater::BED:
+ value = ExtUI::getBedPIDValues_Kp();
+ break;
+ #endif
+ #if ENABLED(PIDTEMP)
+ case DGUS_Data::Heater::H0:
+ value = ExtUI::getPIDValues_Kp(ExtUI::E0);
+ break;
+ #if HAS_MULTI_HOTEND
+ case DGUS_Data::Heater::H1:
+ value = ExtUI::getPIDValues_Kp(ExtUI::E1);
+ break;
+ #endif
+ #endif
+ }
+
+ const int32_t data = dgus_display.ToFixedPoint(value);
+ dgus_display.Write((uint16_t)vp.addr, dgus_display.SwapBytes(data));
+}
+
+void DGUSTxHandler::PIDKi(DGUS_VP &vp) {
+ float value;
+
+ switch (dgus_screen_handler.pid_heater) {
+ default: return;
+ #if ENABLED(PIDTEMPBED)
+ case DGUS_Data::Heater::BED:
+ value = ExtUI::getBedPIDValues_Ki();
+ break;
+ #endif
+ #if ENABLED(PIDTEMP)
+ case DGUS_Data::Heater::H0:
+ value = ExtUI::getPIDValues_Ki(ExtUI::E0);
+ break;
+ #if HAS_MULTI_HOTEND
+ case DGUS_Data::Heater::H1:
+ value = ExtUI::getPIDValues_Ki(ExtUI::E1);
+ break;
+ #endif
+ #endif
+ }
+
+ const int32_t data = dgus_display.ToFixedPoint(value);
+ dgus_display.Write((uint16_t)vp.addr, dgus_display.SwapBytes(data));
+}
+
+void DGUSTxHandler::PIDKd(DGUS_VP &vp) {
+ float value;
+
+ switch (dgus_screen_handler.pid_heater) {
+ default: return;
+ #if ENABLED(PIDTEMPBED)
+ case DGUS_Data::Heater::BED:
+ value = ExtUI::getBedPIDValues_Kd();
+ break;
+ #endif
+ #if ENABLED(PIDTEMP)
+ case DGUS_Data::Heater::H0:
+ value = ExtUI::getPIDValues_Kd(ExtUI::E0);
+ break;
+ #if HAS_MULTI_HOTEND
+ case DGUS_Data::Heater::H1:
+ value = ExtUI::getPIDValues_Kd(ExtUI::E1);
+ break;
+ #endif
+ #endif
+ }
+
+ const int32_t data = dgus_display.ToFixedPoint(value);
+ dgus_display.Write((uint16_t)vp.addr, dgus_display.SwapBytes(data));
+}
+
+void DGUSTxHandler::BuildVolume(DGUS_VP &vp) {
+ char buffer[vp.size];
+ snprintf_P(buffer, vp.size, PSTR("%dx%dx%d"), X_BED_SIZE, Y_BED_SIZE, (Z_MAX_POS - Z_MIN_POS));
+
+ dgus_display.WriteString((uint16_t)vp.addr, buffer, vp.size);
+}
+
+void DGUSTxHandler::TotalPrints(DGUS_VP &vp) {
+ #if ENABLED(PRINTCOUNTER)
+ dgus_display.Write((uint16_t)vp.addr, dgus_display.SwapBytes(print_job_timer.getStats().totalPrints));
+ #else
+ UNUSED(vp);
+ #endif
+}
+
+void DGUSTxHandler::FinishedPrints(DGUS_VP &vp) {
+ #if ENABLED(PRINTCOUNTER)
+ dgus_display.Write((uint16_t)vp.addr, dgus_display.SwapBytes(print_job_timer.getStats().finishedPrints));
+ #else
+ UNUSED(vp);
+ #endif
+}
+
+void DGUSTxHandler::PrintTime(DGUS_VP &vp) {
+ #if ENABLED(PRINTCOUNTER)
+ char buffer[21];
+ ExtUI::getTotalPrintTime_str(buffer);
+
+ dgus_display.WriteString((uint16_t)vp.addr, buffer, vp.size);
+ #else
+ dgus_display.WriteStringPGM((uint16_t)vp.addr, DGUS_MSG_UNDEF, vp.size);
+ #endif
+}
+
+void DGUSTxHandler::LongestPrint(DGUS_VP &vp) {
+ #if ENABLED(PRINTCOUNTER)
+ char buffer[21];
+ ExtUI::getLongestPrint_str(buffer);
+
+ dgus_display.WriteString((uint16_t)vp.addr, buffer, vp.size);
+ #else
+ dgus_display.WriteStringPGM((uint16_t)vp.addr, DGUS_MSG_UNDEF, vp.size);
+ #endif
+}
+
+void DGUSTxHandler::FilamentUsed(DGUS_VP &vp) {
+ #if ENABLED(PRINTCOUNTER)
+ char buffer[21];
+ ExtUI::getFilamentUsed_str(buffer);
+
+ dgus_display.WriteString((uint16_t)vp.addr, buffer, vp.size);
+ #else
+ dgus_display.WriteStringPGM((uint16_t)vp.addr, DGUS_MSG_UNDEF, vp.size);
+ #endif
+}
+
+void DGUSTxHandler::WaitIcons(DGUS_VP &vp) {
+ uint16_t icons = 0;
+
+ if (ExtUI::isPrintingPaused()) {
+ icons |= (uint16_t)DGUS_Data::WaitIcon::ABORT;
+
+ dgus_display.EnableControl(DGUS_Screen::WAIT,
+ DGUSDisplay::POPUP_WINDOW,
+ DGUS_Control::ABORT);
+ }
+ else {
+ dgus_display.DisableControl(DGUS_Screen::WAIT,
+ DGUSDisplay::POPUP_WINDOW,
+ DGUS_Control::ABORT);
+ }
+
+ if (dgus_screen_handler.wait_continue) {
+ icons |= (uint16_t)DGUS_Data::WaitIcon::CONTINUE;
+
+ dgus_display.EnableControl(DGUS_Screen::WAIT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::CONTINUE);
+ }
+ else {
+ dgus_display.DisableControl(DGUS_Screen::WAIT,
+ DGUSDisplay::RETURN_KEY_CODE,
+ DGUS_Control::CONTINUE);
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(icons));
+}
+
+void DGUSTxHandler::FanSpeed(DGUS_VP &vp) {
+ uint16_t fan_speed;
+
+ switch (vp.addr) {
+ default: return;
+ case DGUS_Addr::FAN0_Speed: fan_speed = ExtUI::getTargetFan_percent(ExtUI::FAN0); break;
+ }
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(fan_speed));
+}
+
+void DGUSTxHandler::Volume(DGUS_VP &vp) {
+ const uint16_t volume = dgus_display.GetVolume();
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(volume));
+}
+
+void DGUSTxHandler::Brightness(DGUS_VP &vp) {
+ const uint16_t brightness = dgus_display.GetBrightness();
+
+ dgus_display.Write((uint16_t)vp.addr, Swap16(brightness));
+}
+
+void DGUSTxHandler::ExtraToString(DGUS_VP &vp) {
+ if (!vp.size || !vp.extra) return;
+
+ dgus_display.WriteString((uint16_t)vp.addr, vp.extra, vp.size, true, false, false);
+}
+
+void DGUSTxHandler::ExtraPGMToString(DGUS_VP &vp) {
+ if (!vp.size || !vp.extra) return;
+
+ dgus_display.WriteStringPGM((uint16_t)vp.addr, vp.extra, vp.size, true, false, false);
+}
+
+#endif // DGUS_LCD_UI_RELOADED
diff --git a/src/lcd/extui/dgus_reloaded/DGUSTxHandler.h b/src/lcd/extui/dgus_reloaded/DGUSTxHandler.h
new file mode 100644
index 0000000..94632fe
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/DGUSTxHandler.h
@@ -0,0 +1,126 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+#include "DGUSDisplay.h"
+#include "definition/DGUS_VP.h"
+
+namespace DGUSTxHandler {
+
+ #if ENABLED(SDSUPPORT)
+ void SetFileControlState(int, bool);
+ void FileType(DGUS_VP &);
+ void FileName(DGUS_VP &);
+ void ScrollIcons(DGUS_VP &);
+ void SelectedFileName(DGUS_VP &);
+ #endif
+
+ void PositionZ(DGUS_VP &);
+ void Ellapsed(DGUS_VP &);
+ void Percent(DGUS_VP &);
+ void StatusIcons(DGUS_VP &);
+
+ void Flowrate(DGUS_VP &);
+
+ void TempMax(DGUS_VP &);
+
+ void StepperStatus(DGUS_VP &);
+
+ void StepIcons(DGUS_VP &);
+
+ void ABLDisableIcon(DGUS_VP &);
+ void ABLGrid(DGUS_VP &);
+
+ void FilamentIcons(DGUS_VP &);
+
+ void BLTouch(DGUS_VP &);
+
+ void PIDIcons(DGUS_VP &);
+ void PIDKp(DGUS_VP &);
+ void PIDKi(DGUS_VP &);
+ void PIDKd(DGUS_VP &);
+
+ void BuildVolume(DGUS_VP &);
+ void TotalPrints(DGUS_VP &);
+ void FinishedPrints(DGUS_VP &);
+ void PrintTime(DGUS_VP &);
+ void LongestPrint(DGUS_VP &);
+ void FilamentUsed(DGUS_VP &);
+
+ void WaitIcons(DGUS_VP &);
+
+ void FanSpeed(DGUS_VP &);
+
+ void Volume(DGUS_VP &);
+
+ void Brightness(DGUS_VP &);
+
+ void ExtraToString(DGUS_VP &);
+ void ExtraPGMToString(DGUS_VP &);
+
+ template
+ void ExtraToInteger(DGUS_VP &vp) {
+ if (!vp.size || !vp.extra) return;
+ switch (vp.size) {
+ default: return;
+ case 1: {
+ const uint8_t data = (uint8_t)(*(T*)vp.extra);
+ dgus_display.Write((uint16_t)vp.addr, data);
+ break;
+ }
+ case 2: {
+ const uint16_t data = (uint16_t)(*(T*)vp.extra);
+ dgus_display.Write((uint16_t)vp.addr, Swap16(data));
+ break;
+ }
+ case 4: {
+ const uint32_t data = (uint32_t)(*(T*)vp.extra);
+ dgus_display.Write((uint16_t)vp.addr, dgus_display.SwapBytes(data));
+ break;
+ }
+ }
+ }
+
+ template
+ void ExtraToFixedPoint(DGUS_VP &vp) {
+ if (!vp.size || !vp.extra) return;
+ switch (vp.size) {
+ default: return;
+ case 1: {
+ const uint8_t data = dgus_display.ToFixedPoint(*(T*)vp.extra);
+ dgus_display.Write((uint16_t)vp.addr, data);
+ break;
+ }
+ case 2: {
+ const uint16_t data = dgus_display.ToFixedPoint(*(T*)vp.extra);
+ dgus_display.Write((uint16_t)vp.addr, Swap16(data));
+ break;
+ }
+ case 4: {
+ const uint32_t data = dgus_display.ToFixedPoint(*(T*)vp.extra);
+ dgus_display.Write((uint16_t)vp.addr, dgus_display.SwapBytes(data));
+ break;
+ }
+ }
+ }
+
+}
diff --git a/src/lcd/extui/dgus_reloaded/config/DGUS_Addr.h b/src/lcd/extui/dgus_reloaded/config/DGUS_Addr.h
new file mode 100644
index 0000000..39e9715
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/config/DGUS_Addr.h
@@ -0,0 +1,173 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+constexpr uint8_t DGUS_LINE_LEN = 32;
+constexpr uint8_t DGUS_STATUS_LEN = 32;
+constexpr uint8_t DGUS_FILE_COUNT = 5;
+constexpr uint8_t DGUS_FILENAME_LEN = 32;
+constexpr uint8_t DGUS_ELLAPSED_LEN = 15;
+constexpr uint8_t DGUS_LEVEL_GRID_SIZE = 25;
+constexpr uint8_t DGUS_MACHINE_LEN = 24;
+constexpr uint8_t DGUS_BUILDVOLUME_LEN = 24;
+constexpr uint8_t DGUS_VERSION_LEN = 16;
+constexpr uint8_t DGUS_PRINTTIME_LEN = 24;
+constexpr uint8_t DGUS_LONGESTPRINT_LEN = 24;
+constexpr uint8_t DGUS_FILAMENTUSED_LEN = 24;
+constexpr uint8_t DGUS_GCODE_LEN = 32;
+
+enum class DGUS_Addr : uint16_t {
+ MESSAGE_Line1 = 0x1100, // 0x1100 - 0x111F
+ MESSAGE_Line2 = 0x1120, // 0x1120 - 0x113F
+ MESSAGE_Line3 = 0x1140, // 0x1140 - 0x115F
+ MESSAGE_Line4 = 0x1160, // 0x1160 - 0x117F
+
+ // READ-ONLY VARIABLES
+
+ SCREENCHANGE = 0x2000, // Screen change request. Data contains target screen in low byte.
+ SCREENCHANGE_SD = 0x2001, // Only change if SD card present.
+ SCREENCHANGE_Idle = 0x2002, // Only change if not printing.
+ SCREENCHANGE_Printing = 0x2003, // Only change if printing.
+ SD_SelectFile = 0x2004, // Data: file index (0-4)
+ SD_Scroll = 0x2005, // Data: DGUS_Data::Scroll
+ SD_Print = 0x2006,
+ STATUS_Abort = 0x2007, // Popup / Data: DGUS_Data::Popup
+ STATUS_Pause = 0x2008, // Popup / Data: DGUS_Data::Popup
+ STATUS_Resume = 0x2009, // Popup / Data: DGUS_Data::Popup
+ ADJUST_SetFeedrate = 0x200A, // Type: Integer (16 bits signed)
+ ADJUST_SetFlowrate_CUR = 0x200B, // Type: Integer (16 bits signed)
+ #if HAS_MULTI_EXTRUDER
+ ADJUST_SetFlowrate_E0 = 0x200C, // Type: Integer (16 bits signed)
+ ADJUST_SetFlowrate_E1 = 0x200D, // Type: Integer (16 bits signed)
+ #endif
+ ADJUST_SetBabystep = 0x200E, // Type: Fixed point, 2 decimals (16 bits signed)
+ ADJUST_Babystep = 0x200F, // Data: DGUS_Data::Adjust
+ TEMP_Preset = 0x2010, // Popup / Data: DGUS_Data::TempPreset
+ TEMP_SetTarget_Bed = 0x2011, // Type: Integer (16 bits signed)
+ TEMP_SetTarget_H0 = 0x2012, // Type: Integer (16 bits signed)
+ #if HAS_MULTI_HOTEND
+ TEMP_SetTarget_H1 = 0x2013, // Type: Integer (16 bits signed)
+ #endif
+ TEMP_Cool = 0x2014, // Data: DGUS_Data::Heater
+ STEPPER_Control = 0x2015, // Popup / Data: DGUS_Data::Control
+ LEVEL_OFFSET_Set = 0x2016, // Type: Fixed point, 2 decimals (16 bits signed)
+ LEVEL_OFFSET_Step = 0x2017, // Data: DGUS_Data::Adjust
+ LEVEL_OFFSET_SetStep = 0x2018, // Data: DGUS_Data::StepSize
+ LEVEL_MANUAL_Point = 0x2019, // Data: point index (1-5)
+ LEVEL_AUTO_Probe = 0x201A,
+ LEVEL_AUTO_Disable = 0x201B,
+ FILAMENT_Select = 0x201C, // Data: DGUS_Data::Extruder
+ FILAMENT_SetLength = 0x201D, // Type: Integer (16 bits unsigned)
+ FILAMENT_Move = 0x201E, // Data: DGUS_Data::FilamentMove
+ MOVE_Home = 0x201F, // Data: DGUS_Data::Axis
+ MOVE_SetX = 0x2020, // Type: Fixed point, 1 decimal (16 bits signed)
+ MOVE_SetY = 0x2021, // Type: Fixed point, 1 decimal (16 bits signed)
+ MOVE_SetZ = 0x2022, // Type: Fixed point, 1 decimal (16 bits signed)
+ MOVE_Step = 0x2023, // Data: DGUS_Data::MoveDirection
+ MOVE_SetStep = 0x2024, // Data: DGUS_Data::StepSize
+ GCODE_Clear = 0x2025,
+ GCODE_Execute = 0x2026,
+ EEPROM_Reset = 0x2027, // Popup / Data: DGUS_Data::Popup
+ SETTINGS2_Extra = 0x2028, // Data: DGUS_Data::Extra
+ PID_Select = 0x2029, // Data: DGUS_Data::Heater
+ PID_SetTemp = 0x202A, // Type: Integer (16 bits unsigned)
+ PID_Run = 0x202B,
+ POWERLOSS_Abort = 0x202C, // Popup / Data: DGUS_Data::Popup
+ POWERLOSS_Resume = 0x202D, // Popup / Data: DGUS_Data::Popup
+ WAIT_Abort = 0x202E, // Popup / Data: DGUS_Data::Popup
+ WAIT_Continue = 0x202F,
+
+ // WRITE-ONLY VARIABLES
+
+ MESSAGE_Status = 0x3000, // 0x3000 - 0x301F
+ SD_Type = 0x3020, // 0x3020 - 0x3024 / Data: DGUS_Data::SDType
+ SD_FileName0 = 0x3025, // 0x3025 - 0x3044
+ SD_FileName1 = 0x3045, // 0x3045 - 0x3064
+ SD_FileName2 = 0x3065, // 0x3065 - 0x3084
+ SD_FileName3 = 0x3085, // 0x3085 - 0x30A4
+ SD_FileName4 = 0x30A5, // 0x30A5 - 0x30C4
+ SD_ScrollIcons = 0x30C5, // Bits: DGUS_Data::ScrollIcon
+ SD_SelectedFileName = 0x30C6, // 0x30C6 - 0x30E5
+ STATUS_PositionZ = 0x30E6, // Type: Fixed point, 1 decimal (16 bits signed)
+ STATUS_Ellapsed = 0x30E7, // 0x30E7 - 0x30F5
+ STATUS_Percent = 0x30F6, // Type: Integer (16 bits unsigned)
+ STATUS_Icons = 0x30F7, // Bits: DGUS_Data::StatusIcon
+ ADJUST_Feedrate = 0x30F8, // Type: Integer (16 bits signed)
+ ADJUST_Flowrate_CUR = 0x30F9, // Type: Integer (16 bits signed)
+ #if HAS_MULTI_EXTRUDER
+ ADJUST_Flowrate_E0 = 0x30FA, // Type: Integer (16 bits signed)
+ ADJUST_Flowrate_E1 = 0x30FB, // Type: Integer (16 bits signed)
+ #endif
+ TEMP_Current_Bed = 0x30FC, // Type: Integer (16 bits signed)
+ TEMP_Target_Bed = 0x30FD, // Type: Integer (16 bits signed)
+ TEMP_Max_Bed = 0x30FE, // Type: Integer (16 bits unsigned)
+ TEMP_Current_H0 = 0x30FF, // Type: Integer (16 bits signed)
+ TEMP_Target_H0 = 0x3100, // Type: Integer (16 bits signed)
+ TEMP_Max_H0 = 0x3101, // Type: Integer (16 bits unsigned)
+ #if HAS_MULTI_HOTEND
+ TEMP_Current_H1 = 0x3102, // Type: Integer (16 bits signed)
+ TEMP_Target_H1 = 0x3103, // Type: Integer (16 bits signed)
+ TEMP_Max_H1 = 0x3104, // Type: Integer (16 bits unsigned)
+ #endif
+ STEPPER_Status = 0x3105, // Data: DGUS_Data::Status
+ LEVEL_OFFSET_Current = 0x3106, // Type: Fixed point, 2 decimals (16 bits signed)
+ LEVEL_OFFSET_StepIcons = 0x3107, // Bits: DGUS_Data::StepIcon
+ LEVEL_AUTO_DisableIcon = 0x3108, // Data: DGUS_Data::Status
+ LEVEL_AUTO_Grid = 0x3109, // 0x3109 - 0x3121 / Type: Fixed point, 3 decimals (16 bits signed)
+ LEVEL_PROBING_Icons1 = 0x3122, // Type: Integer (16 bits unsigned) / Each bit represents a grid point
+ LEVEL_PROBING_Icons2 = 0x3123, // Type: Integer (16 bits unsigned) / Each bit represents a grid point
+ FILAMENT_ExtruderIcons = 0x3124, // Data: DGUS_Data::ExtruderIcon
+ FILAMENT_Length = 0x3125, // Type: Integer (16 bits unsigned)
+ MOVE_CurrentX = 0x3126, // Type: Fixed point, 1 decimal (16 bits signed)
+ MOVE_CurrentY = 0x3127, // Type: Fixed point, 1 decimal (16 bits signed)
+ MOVE_CurrentZ = 0x3128, // Type: Fixed point, 1 decimal (16 bits signed)
+ MOVE_StepIcons = 0x3129, // Bits: DGUS_Data::StepIcon
+ SETTINGS2_BLTouch = 0x312A, // Data: DGUS_Data::Status
+ PID_HeaterIcons = 0x312B, // Data: DGUS_Data::HeaterIcon
+ PID_Temp = 0x312C, // Type: Integer (16 bits unsigned)
+ PID_Kp = 0x312D, // Type: Fixed point, 2 decimals (32 bits signed)
+ PID_Ki = 0x312F, // Type: Fixed point, 2 decimals (32 bits signed)
+ PID_Kd = 0x3131, // Type: Fixed point, 2 decimals (32 bits signed)
+ INFOS_Machine = 0x3133, // 0x3133 - 0x314A
+ INFOS_BuildVolume = 0x314B, // 0x314B - 0x3162
+ INFOS_Version = 0x3163, // 0x3163 - 0x3172
+ INFOS_TotalPrints = 0x3173, // Type: Integer (16 bits unsigned)
+ INFOS_FinishedPrints = 0x3174, // Type: Integer (16 bits unsigned)
+ INFOS_PrintTime = 0x3175, // 0x3175 - 0x318C
+ INFOS_LongestPrint = 0x318D, // 0x318D - 0x31A4
+ INFOS_FilamentUsed = 0x31A5, // 0x31A5 - 0x31BC
+ WAIT_Icons = 0x31BD, // Bits: DGUS_Data::WaitIcon
+
+ // READ-WRITE VARIABLES
+
+ FAN0_Speed = 0x4000, // Type: Integer (16 bits unsigned) / Data: fan speed as percent (0-100)
+ GCODE_Data = 0x4001, // 0x4001 - 0x4020
+ PID_Cycles = 0x4021, // Type: Integer (16 bits unsigned)
+ VOLUME_Level = 0x4022, // Type: Integer (16 bits unsigned) / Data: volume as percent (0-100)
+ BRIGHTNESS_Level = 0x4023, // Type: Integer (16 bits unsigned) / Data: brightness as percent (0-100)
+
+ // SPECIAL CASES
+
+ STATUS_Percent_Complete = 0x5000, // Same as STATUS_Percent, but always 100%
+ INFOS_Debug = 0x5001,
+
+};
diff --git a/src/lcd/extui/dgus_reloaded/config/DGUS_Constants.h b/src/lcd/extui/dgus_reloaded/config/DGUS_Constants.h
new file mode 100644
index 0000000..846fd15
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/config/DGUS_Constants.h
@@ -0,0 +1,96 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#include "DGUS_Addr.h"
+
+static_assert((DGUS_LEVEL_GRID_SIZE == GRID_MAX_POINTS_X * GRID_MAX_POINTS_Y), "DGUS_LEVEL_GRID_SIZE incompatible with current mesh.");
+
+#ifndef DGUS_DEFAULT_VOLUME
+ #define DGUS_DEFAULT_VOLUME 50
+#endif
+
+#ifndef DGUS_DEFAULT_BRIGHTNESS
+ #define DGUS_DEFAULT_BRIGHTNESS 100
+#endif
+
+#ifndef DGUS_STATUS_EXPIRATION_MS
+ #define DGUS_STATUS_EXPIRATION_MS 30000
+#endif
+
+#ifndef DGUS_PRINT_BABYSTEP
+ #define DGUS_PRINT_BABYSTEP 0.01f
+#endif
+
+#ifndef DGUS_PLA_TEMP_HOTEND
+ #define DGUS_PLA_TEMP_HOTEND 200
+#endif
+
+#ifndef DGUS_PLA_TEMP_BED
+ #define DGUS_PLA_TEMP_BED 60
+#endif
+
+#ifndef DGUS_ABS_TEMP_HOTEND
+ #define DGUS_ABS_TEMP_HOTEND 240
+#endif
+
+#ifndef DGUS_ABS_TEMP_BED
+ #define DGUS_ABS_TEMP_BED 80
+#endif
+
+#ifndef DGUS_PETG_TEMP_HOTEND
+ #define DGUS_PETG_TEMP_HOTEND 240
+#endif
+
+#ifndef DGUS_PETG_TEMP_BED
+ #define DGUS_PETG_TEMP_BED 60
+#endif
+
+#ifndef DGUS_DEFAULT_FILAMENT_LEN
+ #define DGUS_DEFAULT_FILAMENT_LEN 10
+#endif
+
+#ifndef BED_TRAMMING_Z_HOP
+ #define BED_TRAMMING_Z_HOP 4.0
+#endif
+
+#ifndef BED_TRAMMING_HEIGHT
+ #define BED_TRAMMING_HEIGHT 0.0
+#endif
+
+static_assert(BED_TRAMMING_Z_HOP >= 0, "BED_TRAMMING_Z_HOP must be >= 0. Please update your configuration.");
+
+#ifndef DGUS_LEVEL_CENTER_X
+ #define DGUS_LEVEL_CENTER_X ((X_BED_SIZE) / 2)
+#endif
+
+#ifndef DGUS_LEVEL_CENTER_Y
+ #define DGUS_LEVEL_CENTER_Y ((Y_BED_SIZE) / 2)
+#endif
+
+#if ENABLED(BLTOUCH)
+ #ifndef DGUS_RESET_BLTOUCH
+ #define DGUS_RESET_BLTOUCH "M999\nM280P0S160"
+ #endif
+#endif
diff --git a/src/lcd/extui/dgus_reloaded/config/DGUS_Control.h b/src/lcd/extui/dgus_reloaded/config/DGUS_Control.h
new file mode 100644
index 0000000..650e1e3
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/config/DGUS_Control.h
@@ -0,0 +1,50 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+enum class DGUS_Control : uint8_t {
+
+ // PRINT
+ FILE0 = 1, // RETURN_KEY_CODE
+ FILE1 = 2, // RETURN_KEY_CODE
+ FILE2 = 3, // RETURN_KEY_CODE
+ FILE3 = 4, // RETURN_KEY_CODE
+ FILE4 = 5, // RETURN_KEY_CODE
+ GO_BACK = 6, // RETURN_KEY_CODE
+ SCROLL_UP = 7, // RETURN_KEY_CODE
+ SCROLL_DOWN = 8, // RETURN_KEY_CODE
+
+ // PRINT_STATUS
+ PAUSE = 1, // POPUP_WINDOW
+ RESUME = 2, // POPUP_WINDOW
+
+ // LEVELING_AUTOMATIC
+ DISABLE = 5, // RETURN_KEY_CODE
+
+ // SETTINGS_MENU2
+ EXTRA2 = 6, // RETURN_KEY_CODE
+
+ // WAIT
+ ABORT = 1, // POPUP_WINDOW
+ CONTINUE = 2 // RETURN_KEY_CODE
+
+};
diff --git a/src/lcd/extui/dgus_reloaded/config/DGUS_Data.h b/src/lcd/extui/dgus_reloaded/config/DGUS_Data.h
new file mode 100644
index 0000000..e1c1bf5
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/config/DGUS_Data.h
@@ -0,0 +1,148 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+#include
+
+namespace DGUS_Data {
+
+ // RX constants
+
+ enum class Scroll : uint8_t {
+ GO_BACK = 0,
+ UP = 1,
+ DOWN = 2
+ };
+
+ enum class Popup : uint8_t {
+ CONFIRMED = 1
+ };
+
+ enum class Adjust : uint8_t {
+ INCREMENT = 0,
+ DECREMENT = 1
+ };
+
+ enum class TempPreset : uint8_t {
+ PLA = 1,
+ ABS = 2,
+ PETG = 3
+ };
+
+ enum class Extruder : int8_t {
+ CURRENT = -1,
+ E0 = 0,
+ E1 = 1
+ };
+
+ enum class Heater : int8_t {
+ ALL = -2,
+ BED = -1,
+ H0 = 0,
+ H1 = 1
+ };
+
+ enum class Control : uint8_t {
+ ENABLE = 1,
+ DISABLE = 2
+ };
+
+ enum class StepSize : uint8_t {
+ MM10 = 0, // 10mm
+ MM1 = 1, // 1mm
+ MMP1 = 2, // 0.1mm
+ MMP01 = 3 // 0.01mm
+ };
+
+ enum class FilamentMove : uint8_t {
+ RETRACT = 0,
+ EXTRUDE = 1
+ };
+
+ enum class Axis : uint8_t {
+ X_Y_Z = 0,
+ X_Y = 1,
+ Z = 2
+ };
+
+ enum class MoveDirection : uint8_t {
+ XP = 0, // X+
+ XM = 1, // X-
+ YP = 2, // Y+
+ YM = 3, // Y-
+ ZP = 4, // Z+
+ ZM = 5 // Z-
+ };
+
+ enum class Extra : uint8_t {
+ BUTTON1 = 0,
+ BUTTON2 = 1
+ };
+
+ // TX constants
+
+ enum class SDType : uint16_t {
+ NONE = 0,
+ FILE = 1,
+ DIRECTORY = 2
+ };
+
+ enum class ScrollIcon : uint16_t {
+ GO_BACK = 1U << 0,
+ UP = 1U << 1,
+ DOWN = 1U << 2
+ };
+
+ enum class StatusIcon : uint16_t {
+ PAUSE = 1U << 0,
+ RESUME = 1U << 1
+ };
+
+ enum class Status : uint16_t {
+ DISABLED = 0,
+ ENABLED = 1
+ };
+
+ enum class StepIcon : uint16_t {
+ MM10 = 1U << 0, // 10mm
+ MM1 = 1U << 1, // 1mm
+ MMP1 = 1U << 2, // 0.1mm
+ MMP01 = 1U << 3 // 0.01mm
+ };
+
+ enum class ExtruderIcon : uint16_t {
+ E0 = 1U << 0,
+ E1 = 1U << 1
+ };
+
+ enum class HeaterIcon : uint16_t {
+ BED = 1U << 0,
+ H0 = 1U << 1,
+ H1 = 1U << 2
+ };
+
+ enum class WaitIcon : uint16_t {
+ ABORT = 1U << 0,
+ CONTINUE = 1U << 1
+ };
+
+};
diff --git a/src/lcd/extui/dgus_reloaded/config/DGUS_Screen.h b/src/lcd/extui/dgus_reloaded/config/DGUS_Screen.h
new file mode 100644
index 0000000..0a73822
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/config/DGUS_Screen.h
@@ -0,0 +1,52 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+enum class DGUS_Screen : uint8_t {
+ BOOT = 0,
+ HOME = 1,
+ PRINT = 2,
+ PRINT_STATUS = 3,
+ PRINT_ADJUST = 4,
+ PRINT_FINISHED = 5,
+ TEMP_MENU = 6,
+ TEMP_MANUAL = 7,
+ FAN = 8,
+ SETTINGS_MENU = 9,
+ LEVELING_MENU = 10,
+ LEVELING_OFFSET = 11,
+ LEVELING_MANUAL = 12,
+ LEVELING_AUTOMATIC = 13,
+ LEVELING_PROBING = 14,
+ FILAMENT = 15,
+ MOVE = 16,
+ GCODE = 17,
+ SETTINGS_MENU2 = 18,
+ PID = 19,
+ VOLUME = 20,
+ BRIGHTNESS = 21,
+ INFOS = 22,
+ DEBUG = 240,
+ POWERLOSS = 248,
+ WAIT = 249,
+ KILL = 250
+};
diff --git a/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenAddrList.cpp b/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenAddrList.cpp
new file mode 100644
index 0000000..1627d44
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenAddrList.cpp
@@ -0,0 +1,240 @@
+/**
+ * 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 .
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_RELOADED)
+
+#include "DGUS_ScreenAddrList.h"
+
+#include "../../ui_api.h"
+
+constexpr DGUS_Addr LIST_HOME[] PROGMEM = {
+ DGUS_Addr::TEMP_Current_H0,
+ DGUS_Addr::TEMP_Target_H0,
+ DGUS_Addr::TEMP_Current_Bed,
+ DGUS_Addr::TEMP_Target_Bed,
+ (DGUS_Addr)0
+};
+
+#if ENABLED(SDSUPPORT)
+ constexpr DGUS_Addr LIST_PRINT[] PROGMEM = {
+ DGUS_Addr::SD_Type,
+ DGUS_Addr::SD_FileName0,
+ DGUS_Addr::SD_FileName1,
+ DGUS_Addr::SD_FileName2,
+ DGUS_Addr::SD_FileName3,
+ DGUS_Addr::SD_FileName4,
+ DGUS_Addr::SD_ScrollIcons,
+ DGUS_Addr::SD_SelectedFileName,
+ (DGUS_Addr)0
+ };
+#endif
+
+constexpr DGUS_Addr LIST_PRINT_STATUS[] PROGMEM = {
+ DGUS_Addr::TEMP_Current_H0,
+ DGUS_Addr::TEMP_Target_H0,
+ DGUS_Addr::TEMP_Current_Bed,
+ DGUS_Addr::TEMP_Target_Bed,
+ DGUS_Addr::STATUS_PositionZ,
+ DGUS_Addr::STATUS_Ellapsed,
+ DGUS_Addr::STATUS_Percent,
+ DGUS_Addr::STATUS_Icons,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_PRINT_ADJUST[] PROGMEM = {
+ DGUS_Addr::TEMP_Target_H0,
+ DGUS_Addr::TEMP_Target_Bed,
+ DGUS_Addr::FAN0_Speed,
+ DGUS_Addr::ADJUST_Feedrate,
+ DGUS_Addr::ADJUST_Flowrate_CUR,
+ DGUS_Addr::LEVEL_OFFSET_Current,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_PRINT_FINISHED[] PROGMEM = {
+ DGUS_Addr::TEMP_Current_H0,
+ DGUS_Addr::TEMP_Target_H0,
+ DGUS_Addr::TEMP_Current_Bed,
+ DGUS_Addr::TEMP_Target_Bed,
+ DGUS_Addr::STATUS_PositionZ,
+ DGUS_Addr::STATUS_Ellapsed,
+ DGUS_Addr::STATUS_Percent_Complete,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_TEMP_MENU[] PROGMEM = {
+ DGUS_Addr::TEMP_Current_H0,
+ DGUS_Addr::TEMP_Target_H0,
+ DGUS_Addr::TEMP_Current_Bed,
+ DGUS_Addr::TEMP_Target_Bed,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_TEMP_MANUAL[] PROGMEM = {
+ DGUS_Addr::TEMP_Current_H0,
+ DGUS_Addr::TEMP_Target_H0,
+ DGUS_Addr::TEMP_Max_H0,
+ DGUS_Addr::TEMP_Current_Bed,
+ DGUS_Addr::TEMP_Target_Bed,
+ DGUS_Addr::TEMP_Max_Bed,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_FAN[] PROGMEM = {
+ DGUS_Addr::FAN0_Speed,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_SETTINGS_MENU[] PROGMEM = {
+ DGUS_Addr::STEPPER_Status,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_LEVELING_OFFSET[] PROGMEM = {
+ DGUS_Addr::LEVEL_OFFSET_Current,
+ DGUS_Addr::LEVEL_OFFSET_StepIcons,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_LEVELING_MANUAL[] PROGMEM = {
+ DGUS_Addr::TEMP_Current_H0,
+ DGUS_Addr::TEMP_Target_H0,
+ DGUS_Addr::TEMP_Current_Bed,
+ DGUS_Addr::TEMP_Target_Bed,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_LEVELING_AUTOMATIC[] PROGMEM = {
+ DGUS_Addr::TEMP_Current_H0,
+ DGUS_Addr::TEMP_Target_H0,
+ DGUS_Addr::TEMP_Current_Bed,
+ DGUS_Addr::TEMP_Target_Bed,
+ DGUS_Addr::LEVEL_AUTO_DisableIcon,
+ DGUS_Addr::LEVEL_AUTO_Grid,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_LEVELING_PROBING[] PROGMEM = {
+ DGUS_Addr::LEVEL_PROBING_Icons1,
+ DGUS_Addr::LEVEL_PROBING_Icons2,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_FILAMENT[] PROGMEM = {
+ DGUS_Addr::TEMP_Current_H0,
+ DGUS_Addr::TEMP_Target_H0,
+ DGUS_Addr::FILAMENT_ExtruderIcons,
+ DGUS_Addr::FILAMENT_Length,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_MOVE[] PROGMEM = {
+ DGUS_Addr::MOVE_CurrentX,
+ DGUS_Addr::MOVE_CurrentY,
+ DGUS_Addr::MOVE_CurrentZ,
+ DGUS_Addr::MOVE_StepIcons,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_GCODE[] PROGMEM = {
+ DGUS_Addr::GCODE_Data,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_SETTINGS_MENU2[] PROGMEM = {
+ DGUS_Addr::SETTINGS2_BLTouch,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_PID[] PROGMEM = {
+ DGUS_Addr::PID_HeaterIcons,
+ DGUS_Addr::PID_Temp,
+ DGUS_Addr::PID_Cycles,
+ DGUS_Addr::PID_Kp,
+ DGUS_Addr::PID_Ki,
+ DGUS_Addr::PID_Kd,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_VOLUME[] PROGMEM = {
+ DGUS_Addr::VOLUME_Level,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_BRIGHTNESS[] PROGMEM = {
+ DGUS_Addr::BRIGHTNESS_Level,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_INFOS[] PROGMEM = {
+ DGUS_Addr::INFOS_Machine,
+ DGUS_Addr::INFOS_BuildVolume,
+ DGUS_Addr::INFOS_Version,
+ DGUS_Addr::INFOS_TotalPrints,
+ DGUS_Addr::INFOS_FinishedPrints,
+ DGUS_Addr::INFOS_PrintTime,
+ DGUS_Addr::INFOS_LongestPrint,
+ DGUS_Addr::INFOS_FilamentUsed,
+ (DGUS_Addr)0
+};
+
+constexpr DGUS_Addr LIST_WAIT[] PROGMEM = {
+ DGUS_Addr::WAIT_Icons,
+ (DGUS_Addr)0
+};
+
+#define MAP_HELPER(SCREEN, LIST) \
+ { .screen = SCREEN, \
+ .addr_list = LIST }
+
+const struct DGUS_ScreenAddrList screen_addr_list_map[] PROGMEM = {
+ MAP_HELPER(DGUS_Screen::HOME, LIST_HOME),
+ #if ENABLED(SDSUPPORT)
+ MAP_HELPER(DGUS_Screen::PRINT, LIST_PRINT),
+ #endif
+ MAP_HELPER(DGUS_Screen::PRINT_STATUS, LIST_PRINT_STATUS),
+ MAP_HELPER(DGUS_Screen::PRINT_ADJUST, LIST_PRINT_ADJUST),
+ MAP_HELPER(DGUS_Screen::PRINT_FINISHED, LIST_PRINT_FINISHED),
+ MAP_HELPER(DGUS_Screen::TEMP_MENU, LIST_TEMP_MENU),
+ MAP_HELPER(DGUS_Screen::TEMP_MANUAL, LIST_TEMP_MANUAL),
+ MAP_HELPER(DGUS_Screen::FAN, LIST_FAN),
+ MAP_HELPER(DGUS_Screen::SETTINGS_MENU, LIST_SETTINGS_MENU),
+ MAP_HELPER(DGUS_Screen::LEVELING_OFFSET, LIST_LEVELING_OFFSET),
+ MAP_HELPER(DGUS_Screen::LEVELING_MANUAL, LIST_LEVELING_MANUAL),
+ MAP_HELPER(DGUS_Screen::LEVELING_AUTOMATIC, LIST_LEVELING_AUTOMATIC),
+ MAP_HELPER(DGUS_Screen::LEVELING_PROBING, LIST_LEVELING_PROBING),
+ MAP_HELPER(DGUS_Screen::FILAMENT, LIST_FILAMENT),
+ MAP_HELPER(DGUS_Screen::MOVE, LIST_MOVE),
+ MAP_HELPER(DGUS_Screen::GCODE, LIST_GCODE),
+ MAP_HELPER(DGUS_Screen::SETTINGS_MENU2, LIST_SETTINGS_MENU2),
+ MAP_HELPER(DGUS_Screen::PID, LIST_PID),
+ MAP_HELPER(DGUS_Screen::VOLUME, LIST_VOLUME),
+ MAP_HELPER(DGUS_Screen::BRIGHTNESS, LIST_BRIGHTNESS),
+ MAP_HELPER(DGUS_Screen::INFOS, LIST_INFOS),
+ MAP_HELPER(DGUS_Screen::WAIT, LIST_WAIT),
+
+ MAP_HELPER((DGUS_Screen)0, nullptr)
+};
+
+#endif // DGUS_LCD_UI_RELOADED
diff --git a/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenAddrList.h b/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenAddrList.h
new file mode 100644
index 0000000..1e481ef
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenAddrList.h
@@ -0,0 +1,32 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+#include "../config/DGUS_Screen.h"
+#include "../config/DGUS_Addr.h"
+
+struct DGUS_ScreenAddrList {
+ DGUS_Screen screen;
+ const DGUS_Addr *addr_list;
+};
+
+extern const struct DGUS_ScreenAddrList screen_addr_list_map[];
diff --git a/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenSetup.cpp b/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenSetup.cpp
new file mode 100644
index 0000000..13319ed
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenSetup.cpp
@@ -0,0 +1,57 @@
+/**
+ * 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 .
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_RELOADED)
+
+#include "DGUS_ScreenSetup.h"
+
+#include "../DGUSSetupHandler.h"
+
+#include "../../ui_api.h"
+
+#define SETUP_HELPER(SCREEN, SETUP) \
+ { .screen = SCREEN, \
+ .setup_fn = SETUP }
+
+const struct DGUS_ScreenSetup screen_setup_list[] PROGMEM = {
+ #if ENABLED(SDSUPPORT)
+ SETUP_HELPER(DGUS_Screen::PRINT, &DGUSSetupHandler::Print),
+ #endif
+ SETUP_HELPER(DGUS_Screen::PRINT_STATUS, &DGUSSetupHandler::PrintStatus),
+ SETUP_HELPER(DGUS_Screen::PRINT_ADJUST, &DGUSSetupHandler::PrintAdjust),
+ SETUP_HELPER(DGUS_Screen::LEVELING_MENU, &DGUSSetupHandler::LevelingMenu),
+ SETUP_HELPER(DGUS_Screen::LEVELING_OFFSET, &DGUSSetupHandler::LevelingOffset),
+ SETUP_HELPER(DGUS_Screen::LEVELING_MANUAL, &DGUSSetupHandler::LevelingManual),
+ SETUP_HELPER(DGUS_Screen::LEVELING_AUTOMATIC, &DGUSSetupHandler::LevelingAutomatic),
+ SETUP_HELPER(DGUS_Screen::LEVELING_PROBING, &DGUSSetupHandler::LevelingProbing),
+ SETUP_HELPER(DGUS_Screen::FILAMENT, &DGUSSetupHandler::Filament),
+ SETUP_HELPER(DGUS_Screen::MOVE, &DGUSSetupHandler::Move),
+ SETUP_HELPER(DGUS_Screen::GCODE, &DGUSSetupHandler::Gcode),
+ SETUP_HELPER(DGUS_Screen::PID, &DGUSSetupHandler::PID),
+ SETUP_HELPER(DGUS_Screen::INFOS, &DGUSSetupHandler::Infos),
+
+ SETUP_HELPER((DGUS_Screen)0, nullptr)
+};
+
+#endif // DGUS_LCD_UI_RELOADED
diff --git a/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenSetup.h b/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenSetup.h
new file mode 100644
index 0000000..93df5ad
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/definition/DGUS_ScreenSetup.h
@@ -0,0 +1,31 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+#include "../config/DGUS_Screen.h"
+
+struct DGUS_ScreenSetup {
+ DGUS_Screen screen;
+ bool (*setup_fn)(void);
+};
+
+extern const struct DGUS_ScreenSetup screen_setup_list[];
diff --git a/src/lcd/extui/dgus_reloaded/definition/DGUS_VP.h b/src/lcd/extui/dgus_reloaded/definition/DGUS_VP.h
new file mode 100644
index 0000000..30b3f9d
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/definition/DGUS_VP.h
@@ -0,0 +1,40 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+#include "../config/DGUS_Addr.h"
+
+#define VPFLAG_NONE 0
+#define VPFLAG_AUTOUPLOAD (1U << 0) // Upload on every DGUS update
+#define VPFLAG_RXSTRING (1U << 1) // Treat the received data as a string (terminated with 0xFFFF)
+
+struct DGUS_VP {
+ DGUS_Addr addr;
+ uint8_t size;
+ uint8_t flags;
+ void *extra;
+
+ // Callback that will be called if the display modified the value.
+ // nullptr makes it readonly for the display.
+ void (*rx_handler)(DGUS_VP &, void *);
+ void (*tx_handler)(DGUS_VP &);
+};
diff --git a/src/lcd/extui/dgus_reloaded/definition/DGUS_VPList.cpp b/src/lcd/extui/dgus_reloaded/definition/DGUS_VPList.cpp
new file mode 100644
index 0000000..e77aa45
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/definition/DGUS_VPList.cpp
@@ -0,0 +1,368 @@
+/**
+ * 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 .
+ *
+ */
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_RELOADED)
+
+#include "DGUS_VPList.h"
+
+#include "../config/DGUS_Addr.h"
+#include "../DGUSScreenHandler.h"
+#include "../DGUSRxHandler.h"
+#include "../DGUSTxHandler.h"
+
+#include "../../ui_api.h"
+#include "../../../../module/probe.h"
+#include "../../../../module/motion.h"
+#include "../../../../module/temperature.h"
+
+const char DGUS_MACHINENAME[] PROGMEM = MACHINE_NAME;
+const char DGUS_MARLINVERSION[] PROGMEM = SHORT_BUILD_VERSION;
+
+#define VP_HELPER(ADDR, SIZE, FLAGS, EXTRA, RXHANDLER, TXHANDLER) \
+ { .addr = ADDR, \
+ .size = SIZE, \
+ .flags = FLAGS, \
+ .extra = EXTRA, \
+ .rx_handler = RXHANDLER, \
+ .tx_handler = TXHANDLER }
+
+#define VP_HELPER_WORD(ADDR, FLAGS, EXTRA, RXHANDLER, TXHANDLER) \
+ VP_HELPER(ADDR, 2, FLAGS, EXTRA, RXHANDLER, TXHANDLER)
+
+#define VP_HELPER_DWORD(ADDR, FLAGS, EXTRA, RXHANDLER, TXHANDLER) \
+ VP_HELPER(ADDR, 4, FLAGS, EXTRA, RXHANDLER, TXHANDLER)
+
+#define VP_HELPER_RX(ADDR, RXHANDLER) \
+ VP_HELPER_WORD(ADDR, VPFLAG_NONE, nullptr, RXHANDLER, nullptr)
+
+#define VP_HELPER_RX_NODATA(ADDR, RXHANDLER) \
+ VP_HELPER(ADDR, 0, VPFLAG_NONE, nullptr, RXHANDLER, nullptr)
+
+#define VP_HELPER_TX(ADDR, TXHANDLER) \
+ VP_HELPER_WORD(ADDR, VPFLAG_NONE, nullptr, nullptr, TXHANDLER)
+
+#define VP_HELPER_TX_SIZE(ADDR, SIZE, TXHANDLER) \
+ VP_HELPER(ADDR, SIZE, VPFLAG_NONE, nullptr, nullptr, TXHANDLER)
+
+#define VP_HELPER_TX_EXTRA(ADDR, EXTRA, TXHANDLER) \
+ VP_HELPER_WORD(ADDR, VPFLAG_NONE, EXTRA, nullptr, TXHANDLER)
+
+#define VP_HELPER_TX_AUTO(ADDR, EXTRA, TXHANDLER) \
+ VP_HELPER_WORD(ADDR, VPFLAG_AUTOUPLOAD, EXTRA, nullptr, TXHANDLER)
+
+const struct DGUS_VP vp_list[] PROGMEM = {
+
+ // READ-ONLY VARIABLES
+
+ VP_HELPER_RX(DGUS_Addr::SCREENCHANGE, &DGUSRxHandler::ScreenChange),
+ VP_HELPER_RX(DGUS_Addr::SCREENCHANGE_SD, &DGUSRxHandler::ScreenChange),
+ VP_HELPER_RX(DGUS_Addr::SCREENCHANGE_Idle, &DGUSRxHandler::ScreenChange),
+ VP_HELPER_RX(DGUS_Addr::SCREENCHANGE_Printing, &DGUSRxHandler::ScreenChange),
+
+ #if ENABLED(SDSUPPORT)
+ VP_HELPER_RX(DGUS_Addr::SD_SelectFile, &DGUSRxHandler::SelectFile),
+ VP_HELPER_RX(DGUS_Addr::SD_Scroll, &DGUSRxHandler::Scroll),
+ VP_HELPER_RX_NODATA(DGUS_Addr::SD_Print, &DGUSRxHandler::PrintFile),
+ #endif
+
+ VP_HELPER_RX(DGUS_Addr::STATUS_Abort, &DGUSRxHandler::PrintAbort),
+ VP_HELPER_RX(DGUS_Addr::STATUS_Pause, &DGUSRxHandler::PrintPause),
+ VP_HELPER_RX(DGUS_Addr::STATUS_Resume, &DGUSRxHandler::PrintResume),
+
+ VP_HELPER_RX(DGUS_Addr::ADJUST_SetFeedrate, &DGUSRxHandler::Feedrate),
+ VP_HELPER_RX(DGUS_Addr::ADJUST_SetFlowrate_CUR, &DGUSRxHandler::Flowrate),
+ #if HAS_MULTI_EXTRUDER
+ VP_HELPER_RX(DGUS_Addr::ADJUST_SetFlowrate_E0, &DGUSRxHandler::Flowrate),
+ VP_HELPER_RX(DGUS_Addr::ADJUST_SetFlowrate_E1, &DGUSRxHandler::Flowrate),
+ #endif
+ VP_HELPER_RX(DGUS_Addr::ADJUST_SetBabystep, &DGUSRxHandler::BabystepSet),
+ VP_HELPER_RX(DGUS_Addr::ADJUST_Babystep, &DGUSRxHandler::Babystep),
+
+ VP_HELPER_RX(DGUS_Addr::TEMP_Preset, &DGUSRxHandler::TempPreset),
+ VP_HELPER_RX(DGUS_Addr::TEMP_SetTarget_Bed, &DGUSRxHandler::TempTarget),
+ VP_HELPER_RX(DGUS_Addr::TEMP_SetTarget_H0, &DGUSRxHandler::TempTarget),
+ #if HAS_MULTI_HOTEND
+ VP_HELPER_RX(DGUS_Addr::TEMP_SetTarget_H1, &DGUSRxHandler::TempTarget),
+ #endif
+ VP_HELPER_RX(DGUS_Addr::TEMP_Cool, &DGUSRxHandler::TempCool),
+
+ VP_HELPER_RX(DGUS_Addr::STEPPER_Control, &DGUSRxHandler::Steppers),
+
+ VP_HELPER_RX(DGUS_Addr::LEVEL_OFFSET_Set, &DGUSRxHandler::ZOffset),
+ VP_HELPER_RX(DGUS_Addr::LEVEL_OFFSET_Step, &DGUSRxHandler::ZOffsetStep),
+ VP_HELPER_RX(DGUS_Addr::LEVEL_OFFSET_SetStep, &DGUSRxHandler::ZOffsetSetStep),
+
+ VP_HELPER_RX(DGUS_Addr::LEVEL_MANUAL_Point, &DGUSRxHandler::MoveToPoint),
+
+ VP_HELPER_RX_NODATA(DGUS_Addr::LEVEL_AUTO_Probe, &DGUSRxHandler::Probe),
+ VP_HELPER_RX_NODATA(DGUS_Addr::LEVEL_AUTO_Disable,
+ &DGUSRxHandler::DisableABL),
+
+ VP_HELPER_RX(DGUS_Addr::FILAMENT_Select, &DGUSRxHandler::FilamentSelect),
+ VP_HELPER_RX(DGUS_Addr::FILAMENT_SetLength, &DGUSRxHandler::FilamentLength),
+ VP_HELPER_RX(DGUS_Addr::FILAMENT_Move, &DGUSRxHandler::FilamentMove),
+
+ VP_HELPER_RX(DGUS_Addr::MOVE_Home, &DGUSRxHandler::Home),
+ VP_HELPER_RX(DGUS_Addr::MOVE_SetX, &DGUSRxHandler::Move),
+ VP_HELPER_RX(DGUS_Addr::MOVE_SetY, &DGUSRxHandler::Move),
+ VP_HELPER_RX(DGUS_Addr::MOVE_SetZ, &DGUSRxHandler::Move),
+ VP_HELPER_RX(DGUS_Addr::MOVE_Step, &DGUSRxHandler::MoveStep),
+ VP_HELPER_RX(DGUS_Addr::MOVE_SetStep, &DGUSRxHandler::MoveSetStep),
+
+ VP_HELPER_RX_NODATA(DGUS_Addr::GCODE_Clear, &DGUSRxHandler::GcodeClear),
+ VP_HELPER_RX_NODATA(DGUS_Addr::GCODE_Execute, &DGUSRxHandler::GcodeExecute),
+
+ VP_HELPER_RX(DGUS_Addr::EEPROM_Reset, &DGUSRxHandler::ResetEEPROM),
+
+ VP_HELPER_RX(DGUS_Addr::SETTINGS2_Extra, &DGUSRxHandler::SettingsExtra),
+
+ VP_HELPER_RX(DGUS_Addr::PID_Select, &DGUSRxHandler::PIDSelect),
+ VP_HELPER_RX(DGUS_Addr::PID_SetTemp, &DGUSRxHandler::PIDSetTemp),
+ VP_HELPER_RX_NODATA(DGUS_Addr::PID_Run, &DGUSRxHandler::PIDRun),
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ VP_HELPER_RX(DGUS_Addr::POWERLOSS_Abort, &DGUSRxHandler::PowerLossAbort),
+ VP_HELPER_RX(DGUS_Addr::POWERLOSS_Resume, &DGUSRxHandler::PowerLossResume),
+ #endif
+
+ VP_HELPER_RX(DGUS_Addr::WAIT_Abort, &DGUSRxHandler::WaitAbort),
+ VP_HELPER_RX_NODATA(DGUS_Addr::WAIT_Continue, &DGUSRxHandler::WaitContinue),
+
+ // WRITE-ONLY VARIABLES
+
+ #if ENABLED(SDSUPPORT)
+ VP_HELPER_TX(DGUS_Addr::SD_Type, &DGUSTxHandler::FileType),
+ VP_HELPER_TX_SIZE(DGUS_Addr::SD_FileName0,
+ DGUS_FILENAME_LEN,
+ &DGUSTxHandler::FileName),
+ VP_HELPER_TX_SIZE(DGUS_Addr::SD_FileName1,
+ DGUS_FILENAME_LEN,
+ &DGUSTxHandler::FileName),
+ VP_HELPER_TX_SIZE(DGUS_Addr::SD_FileName2,
+ DGUS_FILENAME_LEN,
+ &DGUSTxHandler::FileName),
+ VP_HELPER_TX_SIZE(DGUS_Addr::SD_FileName3,
+ DGUS_FILENAME_LEN,
+ &DGUSTxHandler::FileName),
+ VP_HELPER_TX_SIZE(DGUS_Addr::SD_FileName4,
+ DGUS_FILENAME_LEN,
+ &DGUSTxHandler::FileName),
+ VP_HELPER_TX(DGUS_Addr::SD_ScrollIcons, &DGUSTxHandler::ScrollIcons),
+ VP_HELPER_TX_SIZE(DGUS_Addr::SD_SelectedFileName,
+ DGUS_FILENAME_LEN,
+ &DGUSTxHandler::SelectedFileName),
+ #endif
+
+ VP_HELPER_TX_AUTO(DGUS_Addr::STATUS_PositionZ,
+ nullptr,
+ &DGUSTxHandler::PositionZ),
+ VP_HELPER(DGUS_Addr::STATUS_Ellapsed,
+ DGUS_ELLAPSED_LEN,
+ VPFLAG_AUTOUPLOAD,
+ nullptr,
+ nullptr,
+ &DGUSTxHandler::Ellapsed),
+ VP_HELPER_TX_AUTO(DGUS_Addr::STATUS_Percent,
+ nullptr,
+ &DGUSTxHandler::Percent),
+ VP_HELPER_TX(DGUS_Addr::STATUS_Icons, &DGUSTxHandler::StatusIcons),
+
+ VP_HELPER_TX_AUTO(DGUS_Addr::ADJUST_Feedrate,
+ &feedrate_percentage,
+ &DGUSTxHandler::ExtraToInteger),
+ VP_HELPER_TX_AUTO(DGUS_Addr::ADJUST_Flowrate_CUR,
+ nullptr,
+ &DGUSTxHandler::Flowrate),
+ #if HAS_MULTI_EXTRUDER
+ VP_HELPER_TX_AUTO(DGUS_Addr::ADJUST_Flowrate_E0,
+ nullptr,
+ &DGUSTxHandler::Flowrate),
+ VP_HELPER_TX_AUTO(DGUS_Addr::ADJUST_Flowrate_E1,
+ nullptr,
+ &DGUSTxHandler::Flowrate),
+ #endif
+
+ VP_HELPER_TX_AUTO(DGUS_Addr::TEMP_Current_Bed,
+ &thermalManager.temp_bed.celsius,
+ &DGUSTxHandler::ExtraToInteger),
+ VP_HELPER_TX_AUTO(DGUS_Addr::TEMP_Target_Bed,
+ &thermalManager.temp_bed.target,
+ &DGUSTxHandler::ExtraToInteger),
+ VP_HELPER_TX(DGUS_Addr::TEMP_Max_Bed, &DGUSTxHandler::TempMax),
+ VP_HELPER_TX_AUTO(DGUS_Addr::TEMP_Current_H0,
+ &thermalManager.temp_hotend[ExtUI::heater_t::H0].celsius,
+ &DGUSTxHandler::ExtraToInteger),
+ VP_HELPER_TX_AUTO(DGUS_Addr::TEMP_Target_H0,
+ &thermalManager.temp_hotend[ExtUI::heater_t::H0].target,
+ &DGUSTxHandler::ExtraToInteger),
+ VP_HELPER_TX(DGUS_Addr::TEMP_Max_H0, &DGUSTxHandler::TempMax),
+ #if HAS_MULTI_HOTEND
+ VP_HELPER_TX_AUTO(DGUS_Addr::TEMP_Current_H1,
+ &thermalManager.temp_hotend[ExtUI::heater_t::H1].celsius,
+ &DGUSTxHandler::ExtraToInteger),
+ VP_HELPER_TX_AUTO(DGUS_Addr::TEMP_Target_H1,
+ &thermalManager.temp_hotend[ExtUI::heater_t::H1].target,
+ &DGUSTxHandler::ExtraToInteger),
+ VP_HELPER_TX(DGUS_Addr::TEMP_Max_H1, &DGUSTxHandler::TempMax),
+ #endif
+
+ VP_HELPER_TX_AUTO(DGUS_Addr::STEPPER_Status,
+ nullptr,
+ &DGUSTxHandler::StepperStatus),
+
+ VP_HELPER_TX_AUTO(DGUS_Addr::LEVEL_OFFSET_Current,
+ &probe.offset.z,
+ (&DGUSTxHandler::ExtraToFixedPoint)),
+ VP_HELPER_TX_EXTRA(DGUS_Addr::LEVEL_OFFSET_StepIcons,
+ &DGUSScreenHandler::offset_steps,
+ &DGUSTxHandler::StepIcons),
+
+ VP_HELPER_TX_AUTO(DGUS_Addr::LEVEL_AUTO_DisableIcon,
+ nullptr,
+ &DGUSTxHandler::ABLDisableIcon),
+ VP_HELPER_TX(DGUS_Addr::LEVEL_AUTO_Grid, &DGUSTxHandler::ABLGrid),
+
+ VP_HELPER_TX_EXTRA(DGUS_Addr::LEVEL_PROBING_Icons1,
+ &DGUSScreenHandler::probing_icons[0],
+ &DGUSTxHandler::ExtraToInteger),
+ VP_HELPER_TX_EXTRA(DGUS_Addr::LEVEL_PROBING_Icons2,
+ &DGUSScreenHandler::probing_icons[1],
+ &DGUSTxHandler::ExtraToInteger),
+
+ VP_HELPER_TX(DGUS_Addr::FILAMENT_ExtruderIcons, &DGUSTxHandler::FilamentIcons),
+ VP_HELPER_TX_EXTRA(DGUS_Addr::FILAMENT_Length,
+ &DGUSScreenHandler::filament_length,
+ &DGUSTxHandler::ExtraToInteger),
+
+ VP_HELPER_TX_AUTO(DGUS_Addr::MOVE_CurrentX,
+ ¤t_position.x,
+ (&DGUSTxHandler::ExtraToFixedPoint)),
+ VP_HELPER_TX_AUTO(DGUS_Addr::MOVE_CurrentY,
+ ¤t_position.y,
+ (&DGUSTxHandler::ExtraToFixedPoint)),
+ VP_HELPER_TX_AUTO(DGUS_Addr::MOVE_CurrentZ,
+ ¤t_position.z,
+ (&DGUSTxHandler::ExtraToFixedPoint)),
+ VP_HELPER_TX_EXTRA(DGUS_Addr::MOVE_StepIcons,
+ &DGUSScreenHandler::move_steps,
+ &DGUSTxHandler::StepIcons),
+
+ VP_HELPER_TX(DGUS_Addr::SETTINGS2_BLTouch, &DGUSTxHandler::BLTouch),
+
+ VP_HELPER_TX(DGUS_Addr::PID_HeaterIcons, &DGUSTxHandler::PIDIcons),
+ VP_HELPER_TX_EXTRA(DGUS_Addr::PID_Temp,
+ &DGUSScreenHandler::pid_temp,
+ &DGUSTxHandler::ExtraToInteger),
+ VP_HELPER_DWORD(DGUS_Addr::PID_Kp,
+ VPFLAG_AUTOUPLOAD,
+ nullptr,
+ nullptr,
+ &DGUSTxHandler::PIDKp),
+ VP_HELPER_DWORD(DGUS_Addr::PID_Ki,
+ VPFLAG_AUTOUPLOAD,
+ nullptr,
+ nullptr,
+ &DGUSTxHandler::PIDKi),
+ VP_HELPER_DWORD(DGUS_Addr::PID_Kd,
+ VPFLAG_AUTOUPLOAD,
+ nullptr,
+ nullptr,
+ &DGUSTxHandler::PIDKd),
+
+ VP_HELPER(DGUS_Addr::INFOS_Machine,
+ DGUS_MACHINE_LEN,
+ VPFLAG_NONE,
+ (void*)DGUS_MACHINENAME,
+ nullptr,
+ &DGUSTxHandler::ExtraPGMToString),
+ VP_HELPER_TX_SIZE(DGUS_Addr::INFOS_BuildVolume,
+ DGUS_BUILDVOLUME_LEN,
+ &DGUSTxHandler::BuildVolume),
+ VP_HELPER(DGUS_Addr::INFOS_Version,
+ DGUS_VERSION_LEN,
+ VPFLAG_NONE,
+ (void*)DGUS_MARLINVERSION,
+ nullptr,
+ &DGUSTxHandler::ExtraPGMToString),
+ VP_HELPER_TX(DGUS_Addr::INFOS_TotalPrints, &DGUSTxHandler::TotalPrints),
+ VP_HELPER_TX(DGUS_Addr::INFOS_FinishedPrints, &DGUSTxHandler::FinishedPrints),
+ VP_HELPER_TX_SIZE(DGUS_Addr::INFOS_PrintTime,
+ DGUS_PRINTTIME_LEN,
+ &DGUSTxHandler::PrintTime),
+ VP_HELPER_TX_SIZE(DGUS_Addr::INFOS_LongestPrint,
+ DGUS_LONGESTPRINT_LEN,
+ &DGUSTxHandler::LongestPrint),
+ VP_HELPER_TX_SIZE(DGUS_Addr::INFOS_FilamentUsed,
+ DGUS_FILAMENTUSED_LEN,
+ &DGUSTxHandler::FilamentUsed),
+
+ VP_HELPER_TX(DGUS_Addr::WAIT_Icons, &DGUSTxHandler::WaitIcons),
+
+ // READ-WRITE VARIABLES
+
+ VP_HELPER(DGUS_Addr::FAN0_Speed,
+ 2,
+ VPFLAG_AUTOUPLOAD,
+ nullptr,
+ &DGUSRxHandler::FanSpeed,
+ &DGUSTxHandler::FanSpeed),
+
+ VP_HELPER(DGUS_Addr::GCODE_Data,
+ DGUS_GCODE_LEN,
+ VPFLAG_RXSTRING,
+ (void*)DGUSScreenHandler::gcode,
+ &DGUSRxHandler::StringToExtra,
+ &DGUSTxHandler::ExtraToString),
+
+ VP_HELPER(DGUS_Addr::PID_Cycles,
+ 2,
+ VPFLAG_NONE,
+ &DGUSScreenHandler::pid_cycles,
+ &DGUSRxHandler::IntegerToExtra,
+ &DGUSTxHandler::ExtraToInteger),
+
+ VP_HELPER(DGUS_Addr::VOLUME_Level,
+ 2,
+ VPFLAG_NONE,
+ nullptr,
+ &DGUSRxHandler::Volume,
+ &DGUSTxHandler::Volume),
+
+ VP_HELPER(DGUS_Addr::BRIGHTNESS_Level,
+ 2,
+ VPFLAG_NONE,
+ nullptr,
+ &DGUSRxHandler::Brightness,
+ &DGUSTxHandler::Brightness),
+
+ // SPECIAL CASES
+
+ VP_HELPER_TX(DGUS_Addr::STATUS_Percent_Complete, &DGUSTxHandler::Percent),
+ VP_HELPER_RX_NODATA(DGUS_Addr::INFOS_Debug, &DGUSRxHandler::Debug),
+
+ VP_HELPER((DGUS_Addr)0, 0, VPFLAG_NONE, nullptr, nullptr, nullptr)
+
+};
+
+#endif // DGUS_LCD_UI_RELOADED
diff --git a/src/lcd/extui/dgus_reloaded/definition/DGUS_VPList.h b/src/lcd/extui/dgus_reloaded/definition/DGUS_VPList.h
new file mode 100644
index 0000000..1a4f368
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/definition/DGUS_VPList.h
@@ -0,0 +1,26 @@
+/**
+ * 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 .
+ *
+ */
+#pragma once
+
+#include "DGUS_VP.h"
+
+extern const struct DGUS_VP vp_list[];
diff --git a/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp b/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp
new file mode 100644
index 0000000..f6f2c0f
--- /dev/null
+++ b/src/lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp
@@ -0,0 +1,143 @@
+/**
+ * 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 .
+ *
+ */
+
+/**
+ * lcd/extui/dgus_reloaded/dgus_reloaded_extui.cpp
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(DGUS_LCD_UI_RELOADED)
+
+#include "../ui_api.h"
+#include "DGUSScreenHandler.h"
+
+namespace ExtUI {
+
+ void onStartup() { dgus_screen_handler.Init(); }
+
+ void onIdle() {
+ static bool processing = false;
+
+ // Prevent recursion
+ if (!processing) {
+ processing = true;
+ dgus_screen_handler.Loop();
+ processing = false;
+ }
+ }
+
+ void onPrinterKilled(FSTR_P const error, FSTR_P const component) {
+ dgus_screen_handler.PrinterKilled(error, component);
+ }
+
+ void onMediaInserted() { TERN_(SDSUPPORT, dgus_screen_handler.SDCardInserted()); }
+ void onMediaError() { TERN_(SDSUPPORT, dgus_screen_handler.SDCardError()); }
+ void onMediaRemoved() { TERN_(SDSUPPORT, dgus_screen_handler.SDCardRemoved()); }
+
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {
+ dgus_screen_handler.PlayTone(frequency, duration);
+ }
+
+ void onPrintTimerStarted() {
+ dgus_screen_handler.PrintTimerStarted();
+ }
+
+ void onPrintTimerPaused() {
+ dgus_screen_handler.PrintTimerPaused();
+ }
+
+ void onPrintTimerStopped() {
+ dgus_screen_handler.PrintTimerStopped();
+ }
+
+ void onFilamentRunout(const extruder_t extruder) {
+ dgus_screen_handler.FilamentRunout(extruder);
+ }
+
+ void onUserConfirmRequired(const char * const msg) {
+ dgus_screen_handler.UserConfirmRequired(msg);
+ }
+
+ void onStatusChanged(const char * const msg) {
+ dgus_screen_handler.SetStatusMessage(msg);
+ }
+
+ void onHomingStart() {}
+ void onHomingDone() {}
+ void onPrintDone() {}
+
+ void onFactoryReset() {
+ dgus_screen_handler.SettingsReset();
+ }
+
+ void onStoreSettings(char *buff) {
+ dgus_screen_handler.StoreSettings(buff);
+ }
+
+ void onLoadSettings(const char *buff) {
+ dgus_screen_handler.LoadSettings(buff);
+ }
+
+ void onPostprocessSettings() {}
+
+ void onSettingsStored(bool success) {
+ dgus_screen_handler.ConfigurationStoreWritten(success);
+ }
+
+ void onSettingsLoaded(bool success) {
+ dgus_screen_handler.ConfigurationStoreRead(success);
+ }
+
+ #if HAS_MESH
+ void onLevelingStart() {}
+ void onLevelingDone() {}
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) {
+ dgus_screen_handler.MeshUpdate(xpos, ypos);
+ }
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const probe_state_t state) {
+ if (state == G29_POINT_FINISH)
+ dgus_screen_handler.MeshUpdate(xpos, ypos);
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {
+ // Called on resume from power-loss
+ dgus_screen_handler.PowerLossResume();
+ }
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ dgus_screen_handler.PidTuning(rst);
+ }
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // DGUS_LCD_UI_RELOADED
diff --git a/src/lcd/extui/example/example.cpp b/src/lcd/extui/example/example.cpp
new file mode 100644
index 0000000..6ef20cf
--- /dev/null
+++ b/src/lcd/extui/example/example.cpp
@@ -0,0 +1,137 @@
+/*********************
+ * example.cpp *
+ *********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if BOTH(EXTUI_EXAMPLE, EXTENSIBLE_UI)
+
+#include "../ui_api.h"
+
+// To implement a new UI, complete the functions below and
+// read or update Marlin's state using the methods in the
+// ExtUI methods in "../ui_api.h"
+//
+// Although it may be possible to access other state
+// variables from Marlin, using the API here possibly
+// helps ensure future compatibility.
+
+namespace ExtUI {
+ void onStartup() {
+ /* Initialize the display module here. The following
+ * routines are available for access to the GPIO pins:
+ *
+ * SET_OUTPUT(pin)
+ * SET_INPUT_PULLUP(pin)
+ * SET_INPUT(pin)
+ * WRITE(pin,value)
+ * READ(pin)
+ */
+ }
+ void onIdle() {}
+ void onPrinterKilled(FSTR_P const error, FSTR_P const component) {}
+ void onMediaInserted() {}
+ void onMediaError() {}
+ void onMediaRemoved() {}
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) {}
+ void onPrintTimerStarted() {}
+ void onPrintTimerPaused() {}
+ void onPrintTimerStopped() {}
+ void onFilamentRunout(const extruder_t extruder) {}
+ void onUserConfirmRequired(const char * const msg) {}
+ void onStatusChanged(const char * const msg) {}
+
+ void onHomingStart() {}
+ void onHomingDone() {}
+ void onPrintDone() {}
+
+ void onFactoryReset() {}
+
+ void onStoreSettings(char *buff) {
+ // Called when saving to EEPROM (i.e. M500). If the ExtUI needs
+ // permanent data to be stored, it can write up to eeprom_data_size bytes
+ // into buff.
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= eeprom_data_size);
+ // memcpy(buff, &myDataStruct, sizeof(myDataStruct));
+ }
+
+ void onLoadSettings(const char *buff) {
+ // Called while loading settings from EEPROM. If the ExtUI
+ // needs to retrieve data, it should copy up to eeprom_data_size bytes
+ // from buff
+
+ // Example:
+ // static_assert(sizeof(myDataStruct) <= eeprom_data_size);
+ // memcpy(&myDataStruct, buff, sizeof(myDataStruct));
+ }
+
+ void onPostprocessSettings() {
+ // Called after loading or resetting stored settings
+ }
+
+ void onSettingsStored(bool success) {
+ // Called after the entire EEPROM has been written,
+ // whether successful or not.
+ }
+
+ void onSettingsLoaded(bool success) {
+ // Called after the entire EEPROM has been read,
+ // whether successful or not.
+ }
+
+ #if HAS_MESH
+ void onLevelingStart() {}
+ void onLevelingDone() {}
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const_float_t zval) {
+ // Called when any mesh points are updated
+ }
+
+ void onMeshUpdate(const int8_t xpos, const int8_t ypos, const probe_state_t state) {
+ // Called to indicate a special condition
+ }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {
+ // Called on resume from power-loss
+ }
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ switch (rst) {
+ case PID_STARTED: break;
+ case PID_BAD_EXTRUDER_NUM: break;
+ case PID_TEMP_TOO_HIGH: break;
+ case PID_TUNING_TIMEOUT: break;
+ case PID_DONE: break;
+ }
+ }
+ #endif
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // EXTUI_EXAMPLE && EXTENSIBLE_UI
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp b/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp
new file mode 100644
index 0000000..a23ad6e
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp
@@ -0,0 +1,552 @@
+/*********************
+ * flash_storage.cpp *
+ *********************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "../ftdi_eve_lib/ftdi_eve_lib.h"
+
+#include "media_file_reader.h"
+#include "flash_storage.h"
+
+// The following must be changed whenever the layout of the flash
+// data is changed in a manner that would render the data invalid.
+
+constexpr uint32_t flash_eeprom_version = 1;
+
+/* SPI Flash Memory Map:
+ *
+ * The following offsets and sizes are specified in 4k erase units:
+ *
+ * Page Size Description
+ * 0 16 DATA STORAGE AREA
+ * 16 1 VERSIONING DATA
+ * 17 inf MEDIA STORAGE AREA
+ */
+
+#define DATA_STORAGE_SIZE_64K
+
+using namespace FTDI::SPI;
+using namespace FTDI::SPI::most_significant_byte_first;
+
+bool UIFlashStorage::is_present = false;
+
+#ifdef SPI_FLASH_SS
+/************************** SPI Flash Chip Interface **************************/
+
+ void SPIFlash::wait_while_busy() {
+ uint8_t status;
+ safe_delay(1);
+ do {
+ spi_flash_select();
+ spi_write_8(READ_STATUS_1);
+ status = spi_read_8();
+ spi_flash_deselect();
+ safe_delay(1);
+ } while (status & 1);
+ }
+
+ void SPIFlash::erase_sector_4k(uint32_t addr) {
+ spi_flash_select();
+ spi_write_8(WRITE_ENABLE);
+ spi_flash_deselect();
+
+ spi_flash_select();
+ spi_write_8(ERASE_4K);
+ spi_write_24(addr);
+ spi_flash_deselect();
+
+ wait_while_busy();
+ }
+
+ void SPIFlash::erase_sector_64k(uint32_t addr) {
+ spi_flash_select();
+ spi_write_8(WRITE_ENABLE);
+ spi_flash_deselect();
+
+ spi_flash_select();
+ spi_write_8(ERASE_64K);
+ spi_write_24(addr);
+ spi_flash_deselect();
+
+ wait_while_busy();
+ }
+
+ void SPIFlash::spi_write_begin(uint32_t addr) {
+ spi_flash_select();
+ spi_write_8(WRITE_ENABLE);
+ spi_flash_deselect();
+
+ spi_flash_select();
+ spi_write_8(PAGE_PROGRAM);
+ spi_write_24(addr);
+ }
+
+ void SPIFlash::spi_write_end() {
+ spi_flash_deselect();
+ wait_while_busy();
+ }
+
+ void SPIFlash::spi_read_begin(uint32_t addr) {
+ spi_flash_select();
+ spi_write_8(READ_DATA);
+ spi_write_24(addr);
+ }
+
+ void SPIFlash::spi_read_end() {
+ spi_flash_deselect();
+ }
+
+ void SPIFlash::erase_chip() {
+ spi_flash_select();
+ spi_write_8(WRITE_ENABLE);
+ spi_flash_deselect();
+
+ spi_flash_select();
+ spi_write_8(ERASE_CHIP);
+ spi_flash_deselect();
+ wait_while_busy();
+ }
+
+ void SPIFlash::read_jedec_id(uint8_t &manufacturer_id, uint8_t &device_type, uint8_t &capacity) {
+ spi_flash_select();
+ spi_write_8(READ_JEDEC_ID);
+ manufacturer_id = spi_recv();
+ device_type = spi_recv();
+ capacity = spi_recv();
+ spi_flash_deselect ();
+ }
+
+ /* This function writes "size" bytes from "data" starting at addr, while properly
+ * taking into account the special case of writing across a 256 byte page boundary.
+ * Returns the addr directly after the write.
+ */
+ uint32_t SPIFlash::write(uint32_t addr, const void *_data, size_t size) {
+ const uint8_t *data = (const uint8_t*) _data;
+ while (size) {
+ const uint32_t page_start = addr & 0xFFFF00ul;
+ const uint32_t page_end = page_start + 256;
+ const uint32_t write_size = min(page_end - addr, size);
+ spi_write_begin(addr);
+ spi_write_bulk(data, write_size);
+ spi_write_end();
+ addr += write_size;
+ size -= write_size;
+ data += write_size;
+ }
+ return addr;
+ }
+
+ uint32_t SPIFlash::read(uint32_t addr, void *data, size_t size) {
+ spi_read_begin(addr);
+ spi_read_bulk(data, size);
+ spi_read_end();
+ return addr + size;
+ }
+
+ /********************************** UTILITY ROUTINES *********************************/
+
+ bool UIFlashStorage::check_known_device() {
+ uint8_t manufacturer_id, device_type, capacity;
+ read_jedec_id(manufacturer_id, device_type, capacity);
+
+ const bool is_known =
+ ((manufacturer_id == 0xEF) && (device_type == 0x40) && (capacity == 0x15)) || // unknown
+ ((manufacturer_id == 0x01) && (device_type == 0x40) && (capacity == 0x15)) || // Cypress S25FL116K
+ ((manufacturer_id == 0xEF) && (device_type == 0x14) && (capacity == 0x15)) || // Winbond W25Q16JV
+ ((manufacturer_id == 0x1F) && (device_type == 0x86) && (capacity == 0x01)) ; // Adesto AT255F161
+
+ if (!is_known) {
+ SERIAL_ECHO_MSG("Unable to locate supported SPI Flash Memory.");
+ SERIAL_ECHO_MSG(" Manufacturer ID, got: ", manufacturer_id);
+ SERIAL_ECHO_MSG(" Device Type , got: ", device_type);
+ SERIAL_ECHO_MSG(" Capacity , got: ", capacity);
+ }
+
+ return is_known;
+ }
+
+ void UIFlashStorage::initialize() {
+ for (uint8_t i = 0; i < 10; i++) {
+ if (check_known_device()) {
+ is_present = true;
+ break;
+ }
+ safe_delay(1000);
+ }
+ }
+
+ /**************************** DATA STORAGE AREA (first 4K or 64k) ********************/
+
+ #ifdef DATA_STORAGE_SIZE_64K
+ constexpr uint32_t data_storage_area_size = 64 * 1024; // Large erase unit
+ #else
+ constexpr uint32_t data_storage_area_size = 4 * 1024; // Small erase unit
+ #endif
+
+ /* In order to provide some degree of wear leveling, each data write to the
+ * SPI Flash chip is appended to data that was already written before, until
+ * the data storage area is completely filled. New data is written preceded
+ * with a 32-bit delimiter 'LULZ', so that we can distinguish written and
+ * unwritten data:
+ *
+ * 'LULZ' <--- 1st record delimiter
+ *
+ *
+ *
+ * 'LULZ' <--- 2nd record delimiter
+ *
+ *
+ *
+ * ...
+ * 'LULZ' <--- Last record delimiter
+ *
+ *
+ *
+ * 0xFF <--- Start of free space
+ * 0xFF
+ * ...
+ *
+ * This function walks down the data storage area, verifying that the
+ * delimiters are either 'LULZ' or 0xFFFFFFFF. In the case that an invalid
+ * delimiter is found, this function returns -1, indicating that the Flash
+ * data is invalid (this will happen if the block_size changed with respect
+ * to earlier firmware). Otherwise, it returns the offset of the last
+ * valid delimiter 'LULZ', indicating the most recently written data.
+ */
+ int32_t UIFlashStorage::get_config_read_offset(uint32_t block_size) {
+ uint16_t stride = 4 + block_size;
+ int32_t read_offset = -1;
+
+ for (uint32_t offset = 0; offset < (data_storage_area_size - stride); offset += stride) {
+ uint32_t delim;
+ spi_read_begin(offset);
+ spi_read_bulk (&delim, sizeof(delim));
+ spi_read_end();
+ switch (delim) {
+ case 0xFFFFFFFFul: return read_offset;
+ case delimiter: read_offset = offset; break;
+ default:
+ SERIAL_ECHO_MSG("Invalid delimiter in Flash: ", delim);
+ return -1;
+ }
+ }
+ SERIAL_ECHO_MSG("No LULZ delimiter found.");
+ return -1;
+ }
+
+ /* This function returns the offset at which new data should be
+ * appended, or -1 if the Flash needs to be erased */
+ int32_t UIFlashStorage::get_config_write_offset(uint32_t block_size) {
+ int32_t read_offset = get_config_read_offset(block_size);
+ if (read_offset == -1) return -1; // The SPI flash is invalid
+
+ int32_t write_offset = read_offset + 4 + block_size;
+ if ((write_offset + 4 + block_size) > data_storage_area_size) {
+ SERIAL_ECHO_MSG("Not enough free space in Flash.");
+ return -1; // Not enough free space
+ }
+ return write_offset;
+ }
+
+ bool UIFlashStorage::verify_config_data(const void *data, size_t size) {
+ if (!is_present) return false;
+
+ int32_t read_addr = get_config_read_offset(size);
+ if (read_addr == -1) return false;
+
+ uint32_t delim;
+ spi_read_begin(read_addr);
+ spi_read_bulk (&delim, sizeof(delim));
+ bool ok = spi_verify_bulk(data,size);
+ spi_read_end();
+ return ok && delim == delimiter;
+ }
+
+ bool UIFlashStorage::read_config_data(void *data, size_t size) {
+ if (!is_present) return false;
+
+ int32_t read_addr = get_config_read_offset(size);
+ if (read_addr == -1) return false;
+
+ uint32_t delim;
+ spi_read_begin(read_addr);
+ spi_read_bulk (&delim, sizeof(delim));
+ spi_read_bulk (data, size);
+ spi_read_end();
+ return delim == delimiter;
+ }
+
+ void UIFlashStorage::write_config_data(const void *data, size_t size) {
+ if (!is_present) {
+ SERIAL_ECHO_MSG("SPI Flash chip not present. Not saving UI settings.");
+ return;
+ }
+
+ // Since Flash storage has a limited number of write cycles,
+ // make sure that the data is different before rewriting.
+
+ if (verify_config_data(data, size)) {
+ SERIAL_ECHO_MSG("UI settings already written, skipping write.");
+ return;
+ }
+
+ int16_t write_addr = get_config_write_offset(size);
+ if (write_addr == -1) {
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPGM("Erasing UI settings from SPI Flash... ");
+ #ifdef DATA_STORAGE_SIZE_64K
+ erase_sector_64k(0);
+ #else
+ erase_sector_4k(0);
+ #endif
+ write_addr = 0;
+ SERIAL_ECHOLNPGM("DONE");
+ }
+
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPGM("Writing UI settings to SPI Flash (offset ", write_addr, ")...");
+
+ const uint32_t delim = delimiter;
+ write_addr = write(write_addr, &delim, sizeof(delim));
+ write_addr = write(write_addr, data, size);
+
+ SERIAL_ECHOLNPGM("DONE");
+ }
+
+ /************************** VERSIONING INFO AREA ************************/
+
+ /* The version info area follows the data storage area. If the version
+ * is incorrect, the data on the chip is invalid and format_flash should
+ * be called.
+ */
+
+ typedef struct {
+ uint32_t magic;
+ uint32_t version;
+ } flash_version_info;
+
+ constexpr uint32_t version_info_addr = data_storage_area_size;
+ constexpr uint32_t version_info_size = 4 * 1024; // Small erase unit
+
+ bool UIFlashStorage::is_valid() {
+ flash_version_info info;
+
+ spi_read_begin(version_info_addr);
+ spi_read_bulk (&info, sizeof(flash_version_info));
+ spi_read_end();
+
+ return info.magic == delimiter && info.version == flash_eeprom_version;
+ }
+
+ void UIFlashStorage::write_version_info() {
+ flash_version_info info;
+
+ info.magic = delimiter;
+ info.version = flash_eeprom_version;
+
+ spi_write_begin(version_info_addr);
+ spi_write_bulk(&info, sizeof(flash_version_info));
+ spi_write_end();
+ }
+
+ /**************************** MEDIA STORAGE AREA *****************************/
+
+ /* The media storage area follows the versioning info area. It consists
+ * of a file index followed by the data for one or more media files.
+ *
+ * The file index consists of an array of 32-bit file sizes. If a file
+ * is not present, the file's size will be set to 0xFFFFFFFF
+ */
+
+ constexpr uint32_t media_storage_addr = version_info_addr + version_info_size;
+ constexpr uint8_t media_storage_slots = 4;
+
+ void UIFlashStorage::format_flash() {
+ SERIAL_ECHO_START(); SERIAL_ECHOPGM("Erasing SPI Flash...");
+ SPIFlash::erase_chip();
+ SERIAL_ECHOLNPGM("DONE");
+
+ write_version_info();
+ }
+
+ uint32_t UIFlashStorage::get_media_file_start(uint8_t slot) {
+ uint32_t addr = media_storage_addr + sizeof(uint32_t) * media_storage_slots;
+ spi_read_begin(media_storage_addr);
+ for (uint8_t i = 0; i < slot; i++)
+ addr += spi_read_32();
+ spi_read_end();
+ return addr;
+ }
+
+ void UIFlashStorage::set_media_file_size(uint8_t slot, uint32_t size) {
+ spi_write_begin(media_storage_addr + sizeof(uint32_t) * slot);
+ spi_write_32(size);
+ spi_write_end();
+ }
+
+ uint32_t UIFlashStorage::get_media_file_size(uint8_t slot) {
+ spi_read_begin(media_storage_addr + sizeof(uint32_t) * slot);
+ uint32_t size = spi_read_32();
+ spi_read_end();
+ return size;
+ }
+
+ /* Writes a media file from the SD card/USB flash drive into a slot on the SPI Flash. Media
+ * files must be written sequentially following by a chip erase and it is not possible to
+ * overwrite files. */
+ UIFlashStorage::error_t UIFlashStorage::write_media_file(FSTR_P filename, uint8_t slot) {
+ #if ENABLED(SDSUPPORT)
+ uint32_t addr;
+ uint8_t buff[write_page_size];
+
+ strcpy_P((char*)buff, FTOP(filename));
+
+ MediaFileReader reader;
+ if (!reader.open((char*) buff)) {
+ SERIAL_ECHO_MSG("Unable to find media file");
+ return FILE_NOT_FOUND;
+ }
+
+ if (get_media_file_size(slot) != 0xFFFFFFFFUL) {
+ SERIAL_ECHO_MSG("Media file already exists");
+ return WOULD_OVERWRITE;
+ }
+
+ SERIAL_ECHO_START(); SERIAL_ECHOPGM("Writing SPI Flash...");
+
+ set_media_file_size(slot, reader.size());
+ addr = get_media_file_start(slot);
+
+ // Write out the file itself
+ for (;;) {
+ const int16_t nBytes = reader.read(buff, write_page_size);
+ if (nBytes == -1) {
+ SERIAL_ECHOLNPGM("Failed to read from file");
+ return READ_ERROR;
+ }
+
+ addr = write(addr, buff, nBytes);
+ if (nBytes != write_page_size) break;
+
+ TERN_(EXTENSIBLE_UI, ExtUI::yield());
+ }
+
+ SERIAL_ECHOLNPGM("DONE");
+
+ SERIAL_ECHO_START(); SERIAL_ECHOPGM("Verifying SPI Flash...");
+
+ bool verifyOk = true;
+
+ // Verify the file index
+
+ if (get_media_file_start(slot+1) != (get_media_file_start(slot) + reader.size())) {
+ SERIAL_ECHOLNPGM("File index verification failed. ");
+ verifyOk = false;
+ }
+
+ // Verify the file itself
+ addr = get_media_file_start(slot);
+ reader.rewind();
+
+ while (verifyOk) {
+ const int16_t nBytes = reader.read(buff, write_page_size);
+ if (nBytes == -1) {
+ SERIAL_ECHOPGM("Failed to read from file");
+ verifyOk = false;
+ break;
+ }
+
+ spi_read_begin(addr);
+ if (!spi_verify_bulk(buff, nBytes)) {
+ verifyOk = false;
+ spi_read_end();
+ break;
+ }
+ spi_read_end();
+
+ addr += nBytes;
+ if (nBytes != write_page_size) break;
+ TERN_(EXTENSIBLE_UI, ExtUI::yield());
+ };
+
+ if (verifyOk) {
+ SERIAL_ECHOLNPGM("DONE");
+ return SUCCESS;
+ }
+ else {
+ SERIAL_ECHOLNPGM("FAIL");
+ return VERIFY_ERROR;
+ }
+ #else
+ return VERIFY_ERROR;
+ #endif // SDSUPPORT
+ }
+
+ bool UIFlashStorage::BootMediaReader::isAvailable(uint32_t slot) {
+ if (!is_present) return false;
+
+ bytes_remaining = get_media_file_size(slot);
+ if (bytes_remaining != 0xFFFFFFFFUL) {
+ SERIAL_ECHO_MSG("Boot media file size:", bytes_remaining);
+ addr = get_media_file_start(slot);
+ return true;
+ }
+ return false;
+ }
+
+ int16_t UIFlashStorage::BootMediaReader::read(void *data, const size_t size) {
+ if (bytes_remaining == 0xFFFFFFFFUL) return -1;
+
+ if (size > bytes_remaining)
+ return read(data, bytes_remaining);
+
+ if (size > 0) {
+ spi_read_begin(addr);
+ spi_read_bulk(data, size);
+ spi_read_end();
+ addr += size;
+ bytes_remaining -= size;
+ }
+
+ return size;
+ }
+
+ int16_t UIFlashStorage::BootMediaReader::read(void *obj, void *data, const size_t size) {
+ return reinterpret_cast(obj)->read(data, size);
+ }
+
+#else
+ void UIFlashStorage::initialize() {}
+ bool UIFlashStorage::is_valid() {return true;}
+ void UIFlashStorage::write_config_data(const void *, size_t) {}
+ bool UIFlashStorage::verify_config_data(const void *, size_t) {return false;}
+ bool UIFlashStorage::read_config_data(void *, size_t ) {return false;}
+ UIFlashStorage::error_t UIFlashStorage::write_media_file(FSTR_P, uint8_t) {return FILE_NOT_FOUND;}
+ void UIFlashStorage::format_flash() {}
+
+ bool UIFlashStorage::BootMediaReader::isAvailable(uint32_t) {return false;}
+ int16_t UIFlashStorage::BootMediaReader::read(void *, const size_t) {return -1;}
+ int16_t UIFlashStorage::BootMediaReader::read(void *, void *, const size_t) {return -1;}
+#endif // SPI_FLASH_SS
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.h b/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.h
new file mode 100644
index 0000000..0ca269a
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/flash_storage.h
@@ -0,0 +1,106 @@
+/*******************
+ * flash_storage.h *
+ *******************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+class SPIFlash {
+ public:
+ static constexpr uint32_t erase_unit_size = 4 * 1024; // Minimum erase unit
+ static constexpr uint32_t write_page_size = 256; // Minimum page write unit
+
+ enum {
+ READ_STATUS_1 = 0x05,
+ READ_STATUS_2 = 0x35,
+ READ_STATUS_3 = 0x33,
+ WRITE_ENABLE = 0x06,
+ WRITE_DISABLE = 0x04,
+ READ_ID = 0x90,
+ READ_JEDEC_ID = 0x9F,
+ READ_DATA = 0x03,
+ PAGE_PROGRAM = 0x02,
+ ERASE_4K = 0x20,
+ ERASE_64K = 0xD8,
+ ERASE_CHIP = 0xC7
+ };
+
+ static void wait_while_busy();
+ static void erase_sector_4k(uint32_t addr);
+ static void erase_sector_64k(uint32_t addr);
+ static void erase_chip ();
+
+ static void read_jedec_id(uint8_t &manufacturer_id, uint8_t &device_type, uint8_t &capacity);
+
+ static void spi_read_begin(uint32_t addr);
+ static void spi_read_end();
+
+ static void spi_write_begin(uint32_t addr);
+ static void spi_write_end();
+
+ static uint32_t write(uint32_t addr, const void *data, size_t size);
+ static uint32_t read(uint32_t addr, void *data, size_t size);
+};
+
+class UIFlashStorage : private SPIFlash {
+ private:
+
+ static bool is_present;
+ static int32_t get_config_read_offset(uint32_t block_size);
+ static int32_t get_config_write_offset(uint32_t block_size);
+
+ static uint32_t get_media_file_start(uint8_t slot);
+ static void set_media_file_size(uint8_t slot, uint32_t size);
+ static uint32_t get_media_file_size(uint8_t slot);
+
+ static constexpr uint32_t delimiter = 0x4D524C4E; // 'MRLN'
+ public:
+ enum error_t {
+ SUCCESS,
+ FILE_NOT_FOUND,
+ READ_ERROR,
+ VERIFY_ERROR,
+ WOULD_OVERWRITE
+ };
+
+ static void initialize ();
+ static void format_flash ();
+ static bool check_known_device();
+
+ static bool is_valid ();
+ static void write_version_info();
+
+ static void write_config_data (const void *data, size_t size);
+ static bool verify_config_data (const void *data, size_t size);
+ static bool read_config_data (void *data, size_t size);
+ static error_t write_media_file (FSTR_P filename, uint8_t slot = 0);
+
+ class BootMediaReader;
+};
+
+class UIFlashStorage::BootMediaReader {
+ private:
+ uint32_t addr;
+ uint32_t bytes_remaining;
+
+ public:
+ bool isAvailable(uint32_t slot = 0);
+ int16_t read(void *buffer, size_t const size);
+
+ static int16_t read(void *obj, void *buffer, const size_t size);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp b/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp
new file mode 100644
index 0000000..b4165a7
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp
@@ -0,0 +1,61 @@
+/************************
+ * media_filereader.cpp *
+ ************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+ #include "media_file_reader.h"
+
+ #if ENABLED(SDSUPPORT)
+ bool MediaFileReader::open(const char *filename) {
+ root = CardReader::getroot();
+ return file.open(&root, filename, O_READ);
+ }
+
+ int16_t MediaFileReader::read(void *buff, size_t bytes) {
+ return file.read(buff, bytes);
+ }
+
+ void MediaFileReader::close() {
+ file.close();
+ }
+
+ uint32_t MediaFileReader::size() {
+ return file.fileSize();
+ }
+
+ void MediaFileReader::rewind() {
+ file.rewind();
+ }
+
+ int16_t MediaFileReader::read(void *obj, void *buff, size_t bytes) {
+ return reinterpret_cast(obj)->read(buff, bytes);
+ }
+ #else
+ bool MediaFileReader::open(const char*) {return -1;}
+ int16_t MediaFileReader::read(void *, size_t) {return 0;}
+ void MediaFileReader::close() {}
+ uint32_t MediaFileReader::size() {return 0;}
+ void MediaFileReader::rewind() {}
+ int16_t MediaFileReader::read(void *, void *, size_t) {return 0;}
+ #endif
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h b/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h
new file mode 100644
index 0000000..eb76bb9
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h
@@ -0,0 +1,46 @@
+/**********************
+ * media_filereader.h *
+ **********************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#include "../../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(SDSUPPORT)
+ #include "../../../../sd/SdFile.h"
+ #include "../../../../sd/cardreader.h"
+#endif
+
+class MediaFileReader {
+ private:
+ #if ENABLED(SDSUPPORT)
+ SdFile root, file;
+ #endif
+
+ public:
+ bool open(const char *filename);
+ int16_t read(void *buff, size_t bytes);
+ uint32_t size();
+ void rewind();
+ void close();
+
+ static int16_t read(void *obj, void *buff, size_t bytes);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/advanced_settings.cpp b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/advanced_settings.cpp
new file mode 100644
index 0000000..e3b95c4
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/advanced_settings.cpp
@@ -0,0 +1,102 @@
+/*************************
+ * advanced_settings.cpp *
+ *************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef FTDI_BIO_ADVANCED_SETTINGS_MENU
+
+using namespace FTDI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 9
+
+void AdvancedSettingsMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true));
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+
+ .tag(2) .button(BTN_POS(1,1), BTN_SIZE(1,1), GET_TEXT_F(MSG_DISPLAY_MENU))
+ .enabled(ENABLED(HAS_TRINAMIC_CONFIG))
+ .tag(3) .button(BTN_POS(1,2), BTN_SIZE(1,1), GET_TEXT_F(MSG_TMC_CURRENT))
+ .enabled(ENABLED(HAS_TRINAMIC_CONFIG))
+ .tag(4) .button(BTN_POS(1,3), BTN_SIZE(1,1), GET_TEXT_F(MSG_TMC_HOMING_THRS))
+ .tag(5) .button(BTN_POS(1,4), BTN_SIZE(1,1), GET_TEXT_F(MSG_LCD_ENDSTOPS))
+ .enabled(ENABLED(HAS_MULTI_HOTEND))
+ .tag(6) .button(BTN_POS(1,5), BTN_SIZE(1,1), GET_TEXT_F(MSG_OFFSETS_MENU))
+
+
+ .tag(7) .button(BTN_POS(2,1), BTN_SIZE(1,1), GET_TEXT_F(MSG_STEPS_PER_MM))
+ .tag(8) .button(BTN_POS(2,2), BTN_SIZE(1,1), GET_TEXT_F(MSG_MAX_SPEED))
+ .tag(9) .button(BTN_POS(2,3), BTN_SIZE(1,1), GET_TEXT_F(MSG_ACCELERATION))
+ .tag(10) .button(BTN_POS(2,4), BTN_SIZE(1,1), GET_TEXT_F(TERN(HAS_JUNCTION_DEVIATION, MSG_JUNCTION_DEVIATION, MSG_JERK)))
+ .enabled(ENABLED(BACKLASH_GCODE))
+ .tag(11) .button(BTN_POS(2,5), BTN_SIZE(1,1), GET_TEXT_F(MSG_BACKLASH))
+ .enabled(ENABLED(LIN_ADVANCE))
+ .tag(12) .button(BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_LINEAR_ADVANCE))
+ .tag(13) .button(BTN_POS(1,7), BTN_SIZE(2,1), GET_TEXT_F(MSG_INTERFACE))
+ .tag(14) .button(BTN_POS(1,8), BTN_SIZE(2,1), GET_TEXT_F(MSG_RESTORE_DEFAULTS))
+ .colors(action_btn)
+ .tag(1) .button( BTN_POS(1,9), BTN_SIZE(2,1), GET_TEXT_F(MSG_BUTTON_DONE));
+ }
+}
+
+bool AdvancedSettingsMenu::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ case 2: GOTO_SCREEN(DisplayTuningScreen); break;
+ #if HAS_TRINAMIC_CONFIG
+ case 3: GOTO_SCREEN(StepperCurrentScreen); break;
+ case 4: GOTO_SCREEN(StepperBumpSensitivityScreen); break;
+ #endif
+ case 5: GOTO_SCREEN(EndstopStatesScreen); break;
+ #if HAS_MULTI_HOTEND
+ case 6: GOTO_SCREEN(NozzleOffsetScreen); break;
+ #endif
+ case 7: GOTO_SCREEN(StepsScreen); break;
+ case 8: GOTO_SCREEN(MaxVelocityScreen); break;
+ case 9: GOTO_SCREEN(DefaultAccelerationScreen); break;
+ case 10: GOTO_SCREEN(TERN(HAS_JUNCTION_DEVIATION, JunctionDeviationScreen, JerkScreen)); break;
+ #if ENABLED(BACKLASH_GCODE)
+ case 11: GOTO_SCREEN(BacklashCompensationScreen); break;
+ #endif
+ #if ENABLED(LIN_ADVANCE)
+ case 12: GOTO_SCREEN(LinearAdvanceScreen); break;
+ #endif
+ case 13: GOTO_SCREEN(InterfaceSettingsScreen); break;
+ case 14: GOTO_SCREEN(RestoreFailsafeDialogBox); break;
+ default: return false;
+ }
+ return true;
+}
+
+#endif // FTDI_BIO_ADVANCED_SETTINGS_MENU
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/advanced_settings.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/advanced_settings.h
new file mode 100644
index 0000000..fc30093
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/advanced_settings.h
@@ -0,0 +1,32 @@
+/***********************
+ * advanced_settings.h *
+ ***********************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define FTDI_BIO_ADVANCED_SETTINGS_MENU
+#define FTDI_BIO_ADVANCED_SETTINGS_MENU_CLASS AdvancedSettingsMenu
+
+class AdvancedSettingsMenu : public BaseScreen, public CachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_e.cpp b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_e.cpp
new file mode 100644
index 0000000..b614ead
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_e.cpp
@@ -0,0 +1,56 @@
+/************************
+ * confirm_home_xyz.cpp *
+ ************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef FTDI_BIO_CONFIRM_HOME_E
+
+using namespace FTDI;
+
+void BioConfirmHomeE::onRedraw(draw_mode_t) {
+ drawMessage(GET_TEXT_F(MSG_HOME_E_WARNING));
+ drawYesNoButtons(1);
+}
+
+bool BioConfirmHomeE::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ #if defined(AXIS_LEVELING_COMMANDS) && defined(PARK_AND_RELEASE_COMMANDS)
+ SpinnerDialogBox::enqueueAndWait(F(
+ "G28 E\n"
+ AXIS_LEVELING_COMMANDS "\n"
+ PARK_AND_RELEASE_COMMANDS
+ ));
+ #endif
+ current_screen.forget();
+ break;
+ case 2:
+ GOTO_SCREEN(StatusScreen);
+ break;
+ default:
+ return DialogBoxBaseClass::onTouchEnd(tag);
+ }
+ return true;
+}
+
+#endif // FTDI_BIO_CONFIRM_HOME_E
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_e.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_e.h
new file mode 100644
index 0000000..34895c9
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_e.h
@@ -0,0 +1,32 @@
+/********************
+ * confirm_home_e.h *
+ ********************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define FTDI_BIO_CONFIRM_HOME_E
+#define FTDI_BIO_CONFIRM_HOME_E_CLASS BioConfirmHomeE
+
+class BioConfirmHomeE : public DialogBoxBaseClass, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_xyz.cpp b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_xyz.cpp
new file mode 100644
index 0000000..8aab340
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_xyz.cpp
@@ -0,0 +1,55 @@
+/************************
+ * confirm_home_xyz.cpp *
+ ************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef FTDI_BIO_CONFIRM_HOME_XYZ
+
+using namespace FTDI;
+
+void BioConfirmHomeXYZ::onRedraw(draw_mode_t) {
+ drawMessage(GET_TEXT_F(MSG_HOME_XYZ_WARNING));
+ drawYesNoButtons(1);
+}
+
+bool BioConfirmHomeXYZ::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ #ifdef PARK_AND_RELEASE_COMMANDS
+ SpinnerDialogBox::enqueueAndWait(F(
+ "G28\n"
+ PARK_AND_RELEASE_COMMANDS
+ ));
+ #endif
+ current_screen.forget();
+ break;
+ case 2:
+ GOTO_SCREEN(StatusScreen);
+ break;
+ default:
+ return DialogBoxBaseClass::onTouchEnd(tag);
+ }
+ return true;
+}
+
+#endif // FTDI_BIO_CONFIRM_HOME_XYZ
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_xyz.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_xyz.h
new file mode 100644
index 0000000..1c1aa36
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/confirm_home_xyz.h
@@ -0,0 +1,32 @@
+/**********************
+ * confirm_home_xyz.h *
+ **********************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define FTDI_BIO_CONFIRM_HOME_XYZ
+#define FTDI_BIO_CONFIRM_HOME_XYZ_CLASS BioConfirmHomeXYZ
+
+class BioConfirmHomeXYZ : public DialogBoxBaseClass, public UncachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/main_menu.cpp b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/main_menu.cpp
new file mode 100644
index 0000000..edae2cb
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/main_menu.cpp
@@ -0,0 +1,85 @@
+/*****************
+ * main_menu.cpp *
+ *****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef FTDI_BIO_MAIN_MENU
+
+using namespace FTDI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 10
+
+void MainMenu::onRedraw(draw_mode_t what) {
+
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(COLOR_RGB(bg_text_enabled))
+ .font(font_large).text( BTN_POS(1,1), BTN_SIZE(2,1), GET_TEXT_F(MSG_MAIN))
+ .colors(normal_btn)
+ .font(font_medium)
+ .tag(2).button(BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_MOVE_TO_HOME))
+ .tag(3).button(BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_RAISE_PLUNGER))
+ .tag(4).button(BTN_POS(1,4), BTN_SIZE(2,1), GET_TEXT_F(MSG_RELEASE_XY_AXIS))
+ .tag(5).button(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_AUTOLEVEL_X_AXIS))
+ .tag(6).button(BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_BED_TEMPERATURE))
+ .tag(7).button(BTN_POS(1,7), BTN_SIZE(2,1), GET_TEXT_F(MSG_INTERFACE))
+ .tag(8).button(BTN_POS(1,8), BTN_SIZE(2,1), GET_TEXT_F(MSG_ADVANCED_SETTINGS))
+ .tag(9).button(BTN_POS(1,9), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_MENU))
+ .colors(action_btn)
+ .tag(1).button(BTN_POS(1,10), BTN_SIZE(2,1), GET_TEXT_F(MSG_BUTTON_DONE));
+ }
+}
+
+bool MainMenu::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+
+ const bool e_homed = isAxisPositionKnown(E0);
+
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ case 2: GOTO_SCREEN(BioConfirmHomeXYZ); break;
+ case 3: SpinnerDialogBox::enqueueAndWait(e_homed ? F("G0 E0 F120") : F("G112")); break;
+ case 4: StatusScreen::unlockMotors(); break;
+ #ifdef AXIS_LEVELING_COMMANDS
+ case 5: SpinnerDialogBox::enqueueAndWait(F(AXIS_LEVELING_COMMANDS)); break;
+ #endif
+ case 6: GOTO_SCREEN(TemperatureScreen); break;
+ case 7: GOTO_SCREEN(InterfaceSettingsScreen); break;
+ case 8: GOTO_SCREEN(AdvancedSettingsMenu); break;
+ case 9: GOTO_SCREEN(AboutScreen); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // FTDI_BIO_MAIN_MENU
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/main_menu.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/main_menu.h
new file mode 100644
index 0000000..37bbe3d
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/main_menu.h
@@ -0,0 +1,32 @@
+/*****************
+ * main_menu.cpp *
+ *****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define FTDI_BIO_MAIN_MENU
+#define FTDI_BIO_MAIN_MENU_CLASS MainMenu
+
+class MainMenu : public BaseScreen, public CachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.cpp b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.cpp
new file mode 100644
index 0000000..4af38dc
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.cpp
@@ -0,0 +1,151 @@
+/***************************
+ * printing_dialog_box.cpp *
+ ***************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef FTDI_BIO_PRINTING_DIALOG_BOX
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 9
+
+void BioPrintingDialogBox::draw_status_message(draw_mode_t what, const char *cmsg) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0);
+ draw_text_box(cmd, BTN_POS(1,2), BTN_SIZE(2,2), cmsg, OPT_CENTER, font_large);
+ }
+}
+
+void BioPrintingDialogBox::draw_progress(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.font(font_large)
+ .text(BTN_POS(1,1), BTN_SIZE(2,2), isPrinting() ? F("Printing...") : F("Finished."))
+ .tag(1)
+ .font(font_xlarge);
+
+ draw_circular_progress(cmd, BTN_POS(1,4), BTN_SIZE(2,3), getProgress_percent(), theme_dark, theme_darkest);
+ }
+}
+
+void BioPrintingDialogBox::draw_time_remaining(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ const uint32_t elapsed = getProgress_seconds_elapsed();
+ const uint8_t hrs = elapsed/3600;
+ const uint8_t min = (elapsed/60)%60;
+
+ char time_str[10];
+ sprintf_P(time_str, PSTR("%02dh %02dm"), hrs, min);
+
+ CommandProcessor cmd;
+ cmd.font(font_large)
+ .text(BTN_POS(1,7), BTN_SIZE(2,2), time_str);
+ }
+}
+
+void BioPrintingDialogBox::draw_interaction_buttons(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(font_medium)
+ .colors(isPrinting() ? action_btn : normal_btn)
+ .tag(2).button(BTN_POS(1,9), BTN_SIZE(1,1), F("Menu"))
+ .enabled(isPrinting() ? TERN0(SDSUPPORT, isPrintingFromMedia()) : 1)
+ .tag(3)
+ .colors(isPrinting() ? normal_btn : action_btn)
+ .button(BTN_POS(2,9), BTN_SIZE(1,1), isPrinting() ? F("Cancel") : F("Back"));
+ }
+}
+
+void BioPrintingDialogBox::onRedraw(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ draw_progress(FOREGROUND);
+ draw_time_remaining(FOREGROUND);
+ draw_interaction_buttons(FOREGROUND);
+ }
+}
+
+bool BioPrintingDialogBox::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_SCREEN(FeedratePercentScreen); break;
+ case 2: GOTO_SCREEN(TuneMenu); break;
+ case 3:
+ if (isPrinting())
+ GOTO_SCREEN(ConfirmAbortPrintDialogBox);
+ else
+ GOTO_SCREEN(StatusScreen);
+ break;
+ default: return false;
+ }
+ return true;
+}
+
+void BioPrintingDialogBox::setStatusMessage(FSTR_P fmsg) {
+ #ifdef __AVR__
+ char buff[strlen_P(FTOP(fmsg)) + 1];
+ strcpy_P(buff, FTOP(fmsg));
+ setStatusMessage(buff);
+ #else
+ setStatusMessage(FTOP(fmsg));
+ #endif
+}
+
+void BioPrintingDialogBox::setStatusMessage(const char *cmsg) {
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true));
+
+ draw_status_message(BACKGROUND, cmsg);
+ draw_progress(BACKGROUND);
+ draw_time_remaining(BACKGROUND);
+ draw_interaction_buttons(BACKGROUND);
+ storeBackground();
+
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("New status message: ", cmsg);
+ #endif
+
+ if (AT_SCREEN(BioPrintingDialogBox))
+ current_screen.onRefresh();
+}
+
+void BioPrintingDialogBox::onIdle() {
+ reset_menu_timeout();
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+
+void BioPrintingDialogBox::show() {
+ GOTO_SCREEN(BioPrintingDialogBox);
+}
+
+#endif // FTDI_BIO_PRINTING_DIALOG_BOX
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.h
new file mode 100644
index 0000000..f260b74
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/printing_dialog_box.h
@@ -0,0 +1,44 @@
+/*************************
+ * printing_dialog_box.h *
+ *************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define FTDI_BIO_PRINTING_DIALOG_BOX
+#define FTDI_BIO_PRINTING_DIALOG_BOX_CLASS BioPrintingDialogBox
+
+class BioPrintingDialogBox : public BaseScreen, public CachedScreen {
+ private:
+ static void draw_status_message(draw_mode_t, const char * const);
+ static void draw_progress(draw_mode_t);
+ static void draw_time_remaining(draw_mode_t);
+ static void draw_interaction_buttons(draw_mode_t);
+ public:
+ static void onRedraw(draw_mode_t);
+
+ static void show();
+
+ static void setStatusMessage(const char *);
+ static void setStatusMessage(FSTR_P);
+
+ static void onIdle();
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/screens.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/screens.h
new file mode 100644
index 0000000..81d4717
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/screens.h
@@ -0,0 +1,105 @@
+/*************
+ * screens.h *
+ *************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+/********************************* DL CACHE SLOTS ******************************/
+
+// In order to reduce SPI traffic, we cache display lists (DL) in RAMG. This
+// is done using the CLCD::DLCache class, which takes a unique ID for each
+// cache location. These IDs are defined here:
+
+enum {
+ STATUS_SCREEN_CACHE,
+ MENU_SCREEN_CACHE,
+ TUNE_SCREEN_CACHE,
+ ALERT_BOX_CACHE,
+ SPINNER_CACHE,
+ ADVANCED_SETTINGS_SCREEN_CACHE,
+ TEMPERATURE_SCREEN_CACHE,
+ STEPS_SCREEN_CACHE,
+ MAX_FEEDRATE_SCREEN_CACHE,
+ MAX_VELOCITY_SCREEN_CACHE,
+ MAX_ACCELERATION_SCREEN_CACHE,
+ DEFAULT_ACCELERATION_SCREEN_CACHE,
+ FLOW_PERCENT_SCREEN_CACHE,
+ ZOFFSET_SCREEN_CACHE,
+ STEPPER_CURRENT_SCREEN_CACHE,
+ STEPPER_BUMP_SENSITIVITY_SCREEN_CACHE,
+ PRINTING_SCREEN_CACHE,
+ FILES_SCREEN_CACHE,
+ INTERFACE_SETTINGS_SCREEN_CACHE,
+ INTERFACE_SOUNDS_SCREEN_CACHE,
+ LOCK_SCREEN_CACHE,
+ DISPLAY_TIMINGS_SCREEN_CACHE
+};
+
+// To save MCU RAM, the status message is "baked" in to the status screen
+// cache, so we reserve a large chunk of memory for the DL cache
+
+#define STATUS_SCREEN_DL_SIZE 4096
+#define ALERT_BOX_DL_SIZE 3072
+#define SPINNER_DL_SIZE 3072
+#define FILE_SCREEN_DL_SIZE 4160
+#define PRINTING_SCREEN_DL_SIZE 2048
+
+/************************* MENU SCREEN DECLARATIONS *************************/
+
+#include "../generic/base_screen.h"
+#include "../generic/base_numeric_adjustment_screen.h"
+#include "../generic/dialog_box_base_class.h"
+#include "../generic/boot_screen.h"
+#include "../generic/about_screen.h"
+#include "../generic/kill_screen.h"
+#include "../generic/alert_dialog_box.h"
+#include "../generic/spinner_dialog_box.h"
+#include "../generic/restore_failsafe_dialog_box.h"
+#include "../generic/save_settings_dialog_box.h"
+#include "../generic/confirm_start_print_dialog_box.h"
+#include "../generic/confirm_abort_print_dialog_box.h"
+#include "../generic/confirm_user_request_alert_box.h"
+#include "../generic/touch_calibration_screen.h"
+#include "../generic/move_axis_screen.h"
+#include "../generic/steps_screen.h"
+#include "../generic/feedrate_percent_screen.h"
+#include "../generic/max_velocity_screen.h"
+#include "../generic/max_acceleration_screen.h"
+#include "../generic/default_acceleration_screen.h"
+#include "../generic/temperature_screen.h"
+#include "../generic/interface_sounds_screen.h"
+#include "../generic/interface_settings_screen.h"
+#include "../generic/lock_screen.h"
+#include "../generic/endstop_state_screen.h"
+#include "../generic/display_tuning_screen.h"
+#include "../generic/media_player_screen.h"
+#include "../generic/statistics_screen.h"
+#include "../generic/stepper_current_screen.h"
+#include "../generic/stepper_bump_sensitivity_screen.h"
+#include "../generic/leveling_menu.h"
+#include "../generic/z_offset_screen.h"
+#include "../generic/files_screen.h"
+
+#include "status_screen.h"
+#include "main_menu.h"
+#include "tune_menu.h"
+#include "advanced_settings.h"
+#include "printing_dialog_box.h"
+#include "confirm_home_xyz.h"
+#include "confirm_home_e.h"
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.cpp b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.cpp
new file mode 100644
index 0000000..9fb56bc
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.cpp
@@ -0,0 +1,376 @@
+/*********************
+ * status_screen.cpp *
+ *********************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef FTDI_BIO_STATUS_SCREEN
+
+#if ENABLED(TOUCH_UI_PORTRAIT)
+ #include "ui_portrait.h"
+#else
+ #include "ui_landscape.h"
+#endif
+
+#define GRID_COLS 2
+#define GRID_ROWS 9
+
+#define POLY(A) PolyUI::poly_reader_t(A, sizeof(A)/sizeof(A[0]))
+
+const uint8_t shadow_depth = 5;
+const float max_speed = 1.00;
+const float min_speed = 0.02;
+const float emax_speed = 2.00;
+const float emin_speed = 0.70;
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+float StatusScreen::increment;
+bool StatusScreen::jog_xy;
+bool StatusScreen::fine_motion;
+
+void StatusScreen::unlockMotors() {
+ injectCommands(F("M84 XY"));
+ jog_xy = false;
+}
+
+void StatusScreen::draw_temperature(draw_mode_t what) {
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ int16_t x, y, h, v;
+
+ cmd.tag(15);
+
+ if (what & BACKGROUND) {
+ cmd.cmd(COLOR_RGB(bg_color));
+
+ // The LulzBot Bio shows the temperature for
+ // the bed.
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ // Draw touch surfaces
+ ui.bounds(POLY(target_temp), x, y, h, v);
+ cmd.rectangle(x, y, h, v);
+ ui.bounds(POLY(actual_temp), x, y, h, v);
+ cmd.rectangle(x, y, h, v);
+ #else
+ ui.bounds(POLY(bed_temp), x, y, h, v);
+ cmd.rectangle(x, y, h, v);
+ #endif
+ ui.bounds(POLY(bed_icon), x, y, h, v);
+ cmd.rectangle(x, y, h, v);
+
+ // Draw bed icon
+ cmd.cmd(BITMAP_SOURCE(Bed_Heat_Icon_Info))
+ .cmd(BITMAP_LAYOUT(Bed_Heat_Icon_Info))
+ .cmd(BITMAP_SIZE (Bed_Heat_Icon_Info))
+ .cmd(COLOR_RGB(shadow_rgb))
+ .icon (x + 2, y + 2, h, v, Bed_Heat_Icon_Info, icon_scale * 2)
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .icon (x, y, h, v, Bed_Heat_Icon_Info, icon_scale * 2);
+
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd); // Restore font bitmap handles
+ #endif
+ }
+
+ if (what & FOREGROUND) {
+ char str[15];
+ cmd.cmd(COLOR_RGB(bg_text_enabled));
+ cmd.font(font_medium);
+
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ if (!isHeaterIdle(BED) && getTargetTemp_celsius(BED) > 0)
+ format_temp(str, getTargetTemp_celsius(BED));
+ else
+ strcpy_P(str, GET_TEXT(MSG_BED));
+
+ ui.bounds(POLY(target_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+
+ format_temp(str, getActualTemp_celsius(BED));
+ ui.bounds(POLY(actual_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ #else
+ if (!isHeaterIdle(BED) && getTargetTemp_celsius(BED) > 0)
+ format_temp_and_temp(str, getActualTemp_celsius(BED), getTargetTemp_celsius(BED));
+ else
+ format_temp_and_idle(str, getActualTemp_celsius(BED));
+
+ ui.bounds(POLY(bed_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ #endif
+ }
+}
+
+void StatusScreen::draw_syringe(draw_mode_t what) {
+ int16_t x, y, h, v;
+ const float fill_level = (
+ #ifdef E_MAX_POS
+ 1.0 - min(1.0, max(0.0, getAxisPosition_mm(E0) / E_MAX_POS))
+ #else
+ 0.75
+ #endif
+ );
+ const bool e_homed = TERN1(TOUCH_UI_LULZBOT_BIO, isAxisPositionKnown(E0));
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ if (what & BACKGROUND) {
+ // Paint the shadow for the syringe
+ ui.color(shadow_rgb);
+ ui.shadow(POLY(syringe_outline), shadow_depth);
+ }
+
+ if (what & FOREGROUND && e_homed) {
+ // Paint the syringe icon
+ ui.color(syringe_rgb);
+ ui.fill(POLY(syringe_outline));
+
+ ui.color(fluid_rgb);
+ ui.bounds(POLY(syringe_fluid), x, y, h, v);
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(SCISSOR_XY(x,y + v * (1.0 - fill_level)));
+ cmd.cmd(SCISSOR_SIZE(h, v * fill_level));
+ ui.fill(POLY(syringe_fluid), false);
+ cmd.cmd(RESTORE_CONTEXT());
+
+ ui.color(stroke_rgb);
+ ui.fill(POLY(syringe));
+ }
+}
+
+void StatusScreen::draw_arrows(draw_mode_t what) {
+ const bool e_homed = TERN1(TOUCH_UI_LULZBOT_BIO, isAxisPositionKnown(E0)),
+ z_homed = isAxisPositionKnown(Z);
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ ui.button_fill (fill_rgb);
+ ui.button_stroke(stroke_rgb, 28);
+ ui.button_shadow(shadow_rgb, shadow_depth);
+
+ constexpr uint8_t style = PolyUI::REGULAR;
+
+ if ((what & BACKGROUND) || jog_xy) {
+ ui.button(1, POLY(x_neg), style);
+ ui.button(2, POLY(x_pos), style);
+ ui.button(3, POLY(y_neg), style);
+ ui.button(4, POLY(y_pos), style);
+ }
+
+ if ((what & BACKGROUND) || z_homed) {
+ ui.button(5, POLY(z_neg), style);
+ ui.button(6, POLY(z_pos), style);
+ }
+
+ if ((what & BACKGROUND) || e_homed) {
+ ui.button(7, POLY(e_neg), style);
+ ui.button(8, POLY(e_pos), style);
+ }
+}
+
+void StatusScreen::draw_fine_motion(draw_mode_t what) {
+ int16_t x, y, h, v;
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ cmd.font(
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ font_medium
+ #else
+ font_small
+ #endif
+ )
+ .tag(16);
+
+ if (what & BACKGROUND) {
+ ui.bounds(POLY(fine_label), x, y, h, v);
+ cmd.cmd(COLOR_RGB(bg_text_enabled))
+ .text(x, y, h, v, GET_TEXT_F(MSG_FINE_MOTION));
+ }
+
+ if (what & FOREGROUND) {
+ ui.bounds(POLY(fine_toggle), x, y, h, v);
+ cmd.colors(ui_toggle)
+ .toggle2(x, y, h, v, GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), fine_motion);
+ }
+}
+
+void StatusScreen::draw_overlay_icons(draw_mode_t what) {
+ const bool e_homed = TERN1(TOUCH_UI_LULZBOT_BIO, isAxisPositionKnown(E0)),
+ z_homed = isAxisPositionKnown(Z);
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ if (what & FOREGROUND) {
+ ui.button_fill (fill_rgb);
+ ui.button_stroke(stroke_rgb, 28);
+ ui.button_shadow(shadow_rgb, shadow_depth);
+
+ constexpr uint8_t style = PolyUI::REGULAR;
+ if (!jog_xy) ui.button(12, POLY(padlock), style);
+ if (!e_homed) ui.button(13, POLY(home_e), style);
+ if (!z_homed) ui.button(14, POLY(home_z), style);
+ }
+}
+
+void StatusScreen::draw_buttons(draw_mode_t what) {
+ int16_t x, y, h, v;
+
+ const bool has_media = isMediaInserted() && !isPrintingFromMedia();
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ ui.bounds(POLY(usb_btn), x, y, h, v);
+ cmd.font(font_medium)
+ .colors(normal_btn)
+ .enabled(has_media)
+ .colors(has_media ? action_btn : normal_btn)
+ .tag(9).button(x, y, h, v,
+ isPrintingFromMedia() ?
+ GET_TEXT_F(MSG_PRINTING) :
+ GET_TEXT_F(MSG_BUTTON_MEDIA)
+ );
+
+ ui.bounds(POLY(menu_btn), x, y, h, v);
+ cmd.colors(!has_media ? action_btn : normal_btn).tag(10).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_MENU));
+}
+
+void StatusScreen::loadBitmaps() {
+ // Load the bitmaps for the status screen
+ constexpr uint32_t base = ftdi_memory_map::RAM_G;
+ CLCD::mem_write_pgm(base + Bed_Heat_Icon_Info.RAMG_offset, Bed_Heat_Icon, sizeof(Bed_Heat_Icon));
+
+ // Load fonts for internationalization
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_data(base + UTF8_FONT_OFFSET);
+ #endif
+}
+
+void StatusScreen::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ draw_syringe(what);
+ draw_temperature(what);
+ draw_arrows(what);
+ draw_overlay_icons(what);
+ draw_buttons(what);
+ draw_fine_motion(what);
+}
+
+bool StatusScreen::onTouchStart(uint8_t) {
+ increment = 0;
+ return true;
+}
+
+bool StatusScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 12:
+ if (!jog_xy) {
+ jog_xy = true;
+ injectCommands(F("M17"));
+ }
+ jog({ 0, 0, 0 });
+ break;
+ case 5:
+ case 6:
+ jog({ 0, 0, 0 });
+ break;
+ case 9: GOTO_SCREEN(FilesScreen); break;
+ case 10: GOTO_SCREEN(MainMenu); break;
+ case 13: GOTO_SCREEN(BioConfirmHomeE); break;
+ case 14: SpinnerDialogBox::enqueueAndWait(F("G28Z")); break;
+ case 15: GOTO_SCREEN(TemperatureScreen); break;
+ case 16: fine_motion = !fine_motion; break;
+ default: return false;
+ }
+ // If a passcode is enabled, the LockScreen will prevent the
+ // user from proceeding.
+ LockScreen::check_passcode();
+ return true;
+}
+
+bool StatusScreen::onTouchHeld(uint8_t tag) {
+ if (tag >= 1 && tag <= 4 && !jog_xy) return false;
+ const float s = min_speed + (fine_motion ? 0 : (max_speed - min_speed) * sq(increment));
+ switch (tag) {
+ case 1: jog({-s, 0, 0}); break;
+ case 2: jog({ s, 0, 0}); break;
+ case 4: jog({ 0, -s, 0}); break; // NOTE: Y directions inverted because bed rather than needle moves
+ case 3: jog({ 0, s, 0}); break;
+ case 5: jog({ 0, 0, -s}); break;
+ case 6: jog({ 0, 0, s}); break;
+ case 7: case 8:
+ {
+ if (ExtUI::isMoving()) return false;
+ const feedRate_t feedrate = emin_speed + (fine_motion ? 0 : (emax_speed - emin_speed) * sq(increment));
+ const float increment = 0.25 * feedrate * (tag == 7 ? -1 : 1);
+ MoveAxisScreen::setManualFeedrate(E0, feedrate);
+ UI_INCREMENT(AxisPosition_mm, E0);
+ current_screen.onRefresh();
+ break;
+ }
+ default:
+ return false;
+ }
+ increment = min(1.0f, increment + 0.1f);
+ return false;
+}
+
+void StatusScreen::setStatusMessage(FSTR_P fstr) {
+ BioPrintingDialogBox::setStatusMessage(fstr);
+}
+
+void StatusScreen::setStatusMessage(const char * const str) {
+ BioPrintingDialogBox::setStatusMessage(str);
+}
+
+void StatusScreen::onIdle() {
+ reset_menu_timeout();
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ if (!EventLoop::is_touch_held())
+ onRefresh();
+ if (isPrintingFromMedia())
+ BioPrintingDialogBox::show();
+ refresh_timer.start();
+ }
+}
+
+#endif // FTDI_BIO_STATUS_SCREEN
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.h
new file mode 100644
index 0000000..d074e82
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/status_screen.h
@@ -0,0 +1,56 @@
+/*********************
+ * status_screen.cpp *
+ *********************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define FTDI_BIO_STATUS_SCREEN
+#define FTDI_BIO_STATUS_SCREEN_CLASS StatusScreen
+
+class StatusScreen : public BaseScreen, public CachedScreen {
+ private:
+ static float increment;
+ static bool jog_xy;
+ static bool fine_motion;
+
+ static void draw_progress(draw_mode_t what);
+ static void draw_temperature(draw_mode_t what);
+ static void draw_syringe(draw_mode_t what);
+ static void draw_arrows(draw_mode_t what);
+ static void draw_overlay_icons(draw_mode_t what);
+ static void draw_fine_motion(draw_mode_t what);
+ static void draw_buttons(draw_mode_t what);
+ public:
+ static void loadBitmaps();
+ static void unlockMotors();
+
+ static void setStatusMessage(const char *);
+ static void setStatusMessage(FSTR_P);
+
+ static void onRedraw(draw_mode_t);
+
+ static bool onTouchStart(uint8_t tag);
+ static bool onTouchHeld(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+ static void onIdle();
+
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/tune_menu.cpp b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/tune_menu.cpp
new file mode 100644
index 0000000..d5b3897
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/tune_menu.cpp
@@ -0,0 +1,76 @@
+/*****************
+ * tune_menu.cpp *
+ *****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef FTDI_BIO_TUNE_MENU
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+#define GRID_COLS 2
+#define GRID_ROWS 8
+
+void TuneMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0)
+ .font(font_large)
+ .text( BTN_POS(1,1), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_MENU));
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(font_medium)
+ .enabled( isPrinting()).tag(2).button(BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_SPEED))
+ .tag(3).button(BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_BED_TEMPERATURE))
+ .enabled(TERN_(BABYSTEPPING, true))
+ .tag(4).button(BTN_POS(1,4), BTN_SIZE(2,1), GET_TEXT_F(MSG_NUDGE_NOZZLE))
+ .enabled(!isPrinting()).tag(5).button(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_MOVE_TO_HOME))
+ .enabled(!isPrinting()).tag(6).button(BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_RAISE_PLUNGER))
+ .enabled(!isPrinting()).tag(7).button(BTN_POS(1,7), BTN_SIZE(2,1), GET_TEXT_F(MSG_RELEASE_XY_AXIS))
+ .colors(action_btn) .tag(1).button(BTN_POS(1,8), BTN_SIZE(2,1), GET_TEXT_F(MSG_BUTTON_DONE));
+ }
+}
+
+bool TuneMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ case 2: GOTO_SCREEN(FeedratePercentScreen); break;
+ case 3: GOTO_SCREEN(TemperatureScreen); break;
+ case 4: GOTO_SCREEN(NudgeNozzleScreen); break;
+ case 5: GOTO_SCREEN(BioConfirmHomeXYZ); break;
+ case 6: SpinnerDialogBox::enqueueAndWait(F("G0 E0 F120")); break;
+ case 7: StatusScreen::unlockMotors(); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // FTDI_BIO_TUNE_MENU
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/tune_menu.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/tune_menu.h
new file mode 100644
index 0000000..8677bb5
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/tune_menu.h
@@ -0,0 +1,35 @@
+/***************
+ * tune_menu.h *
+ ***************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define FTDI_BIO_TUNE_MENU
+#define FTDI_BIO_TUNE_MENU_CLASS TuneMenu
+
+class TuneMenu : public BaseScreen, public CachedScreen {
+ private:
+ static void pausePrint();
+ static void resumePrint();
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/ui_landscape.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/ui_landscape.h
new file mode 100644
index 0000000..dc70f6c
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/ui_landscape.h
@@ -0,0 +1,61 @@
+/******************
+ * ui_landscape.h *
+ ******************/
+
+/****************************************************************************
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+#pragma once
+
+constexpr float x_min = 0.000000;
+constexpr float x_max = 480.000000;
+constexpr float y_min = 0.000000;
+constexpr float y_max = 272.000000;
+
+const PROGMEM uint16_t z_neg[] = {0x7950, 0x51EA, 0x824E, 0x51EA, 0x824E, 0x71E2, 0x86CD, 0x71E2, 0x7DCF, 0x81DF, 0x74D1, 0x71E2, 0x7950, 0x71E2, 0x7950, 0x51EA};
+const PROGMEM uint16_t z_pos[] = {0x7950, 0x41EE, 0x824E, 0x41EE, 0x824E, 0x21F5, 0x86CD, 0x21F5, 0x7DCF, 0x11F9, 0x74D0, 0x21F5, 0x7950, 0x21F5, 0x7950, 0x41EE};
+const PROGMEM uint16_t y_neg[] = {0x3479, 0x56CF, 0x3EC6, 0x56CF, 0x3747, 0x7281, 0x3C6D, 0x7281, 0x2E61, 0x8059, 0x27D4, 0x7281, 0x2CFA, 0x7281, 0x3479, 0x56CF};
+const PROGMEM uint16_t y_pos[] = {0x3BF9, 0x3B1D, 0x4645, 0x3B1D, 0x4DC4, 0x1F6B, 0x52EB, 0x1F6B, 0x4C5E, 0x1192, 0x3E52, 0x1F6B, 0x4378, 0x1F6B, 0x3BF9, 0x3B1D};
+const PROGMEM uint16_t x_neg[] = {0x350E, 0x4209, 0x314E, 0x4FE2, 0x1CB5, 0x4FE2, 0x1AD6, 0x56CF, 0x1449, 0x48F6, 0x2255, 0x3B1D, 0x2075, 0x4209, 0x350E, 0x4209};
+const PROGMEM uint16_t x_pos[] = {0x498C, 0x4209, 0x45CC, 0x4FE2, 0x5A65, 0x4FE2, 0x5885, 0x56CF, 0x6691, 0x48F6, 0x6004, 0x3B1D, 0x5E25, 0x4209, 0x498C, 0x4209};
+const PROGMEM uint16_t syringe_fluid[] = {0xB4E9, 0x78BE, 0xBB12, 0x7C44, 0xBDE3, 0x7C44, 0xC426, 0x78BE, 0xC426, 0x250D, 0xB4E9, 0x250D, 0xB4E9, 0x78BE};
+const PROGMEM uint16_t syringe[] = {0xB8AD, 0x6BB1, 0xB8AD, 0x6E0C, 0xBE02, 0x6E0C, 0xBE02, 0x6BB1, 0xFFFF, 0xB8AD, 0x6248, 0xB8AD, 0x64A2, 0xBE02, 0x64A2, 0xBE02, 0x6248, 0xFFFF, 0xB8AD, 0x58DF, 0xB8AD, 0x5B39, 0xBE02, 0x5B39, 0xBE02, 0x58DF, 0xFFFF, 0xB8AD, 0x4F75, 0xB8AD, 0x51D0, 0xBE02, 0x51D0, 0xBE02, 0x4F75, 0xFFFF, 0xB8AD, 0x460C, 0xB8AD, 0x4866, 0xBE02, 0x4866, 0xBE02, 0x460C, 0xFFFF, 0xB8AD, 0x3CA3, 0xB8AD, 0x3EFD, 0xBE02, 0x3EFD, 0xBE02, 0x3CA3, 0xFFFF, 0xB8AD, 0x3339, 0xB8AD, 0x3594, 0xBE02, 0x3594, 0xBE02, 0x3339, 0xFFFF, 0xB396, 0x110A, 0xB396, 0x1818, 0xB995, 0x1818, 0xB995, 0x22AD, 0xB396, 0x22AD, 0xB396, 0x7ADA, 0xB995, 0x7E61, 0xB995, 0x88F5, 0xBB95, 0x88F5, 0xBB95, 0xA8B4, 0xBD94, 0xAC3B, 0xBD94, 0x88F5, 0xBF94, 0x88F5, 0xBF94, 0x7E61, 0xC593, 0x7ADA, 0xC593, 0x22AD, 0xBF94, 0x22AD, 0xBF94, 0x1818, 0xC593, 0x1818, 0xC593, 0x110A, 0xFFFF, 0xBB95, 0x1818, 0xBD94, 0x1818, 0xBD94, 0x22AD, 0xBB95, 0x22AD, 0xBB95, 0x1818, 0xFFFF, 0xB596, 0x2634, 0xC393, 0x2634, 0xC393, 0x7753, 0xBD94, 0x7ADA, 0xBB95, 0x7ADA, 0xB596, 0x7753, 0xB596, 0x2634};
+const PROGMEM uint16_t syringe_outline[] = {0xB396, 0x110A, 0xB396, 0x1818, 0xB995, 0x1818, 0xB995, 0x22AD, 0xB396, 0x22AD, 0xB396, 0x7ADA, 0xB995, 0x7E61, 0xB995, 0x88F5, 0xBB95, 0x88F5, 0xBB95, 0xA8B4, 0xBD94, 0xAC3B, 0xBD94, 0x88F5, 0xBF94, 0x88F5, 0xBF94, 0x7E61, 0xC593, 0x7ADA, 0xC593, 0x22AD, 0xBF94, 0x22AD, 0xBF94, 0x1818, 0xC593, 0x1818, 0xC593, 0x110A, 0xB396, 0x110A};
+const PROGMEM uint16_t padlock[] = {0x3FE3, 0x2A04, 0x3D34, 0x2AF9, 0x3AFF, 0x2D93, 0x397D, 0x316D, 0x38E8, 0x3626, 0x38E8, 0x3A14, 0x39B3, 0x3C8F, 0x3B50, 0x3C8F, 0x3C1C, 0x3A14, 0x3C1C, 0x363C, 0x3C6B, 0x33A9, 0x3D3A, 0x3193, 0x3E6C, 0x302D, 0x3FE3, 0x2FAA, 0x415A, 0x302D, 0x428C, 0x3192, 0x435B, 0x33A8, 0x43AB, 0x363C, 0x43AB, 0x4492, 0x38C3, 0x4492, 0x3741, 0x45AC, 0x36A1, 0x4856, 0x36A1, 0x5C41, 0x3741, 0x5EEC, 0x38C3, 0x6005, 0x4703, 0x6005, 0x4886, 0x5EEC, 0x4925, 0x5C41, 0x4925, 0x4856, 0x4886, 0x45AC, 0x4703, 0x4492, 0x46DE, 0x362B, 0x4649, 0x316D, 0x44C7, 0x2D92, 0x4292, 0x2AF9};
+const PROGMEM uint16_t home_z[] = {0x80BB, 0x2B43, 0x712C, 0x46B9, 0x750F, 0x46B9, 0x750F, 0x622F, 0x7CD7, 0x622F, 0x7CD7, 0x5474, 0x849F, 0x5474, 0x849F, 0x622F, 0x8C67, 0x622F, 0x8C67, 0x46B9, 0x904B, 0x46B9, 0x8A48, 0x3C1D, 0x8A48, 0x2ECD, 0x8664, 0x2ECD, 0x8664, 0x3540};
+const PROGMEM uint16_t usb_btn[] = {0x0558, 0xC0D6, 0x3BDB, 0xC0D6, 0x3BDB, 0xF431, 0x0558, 0xF431, 0x0558, 0xC0D6};
+const PROGMEM uint16_t menu_btn[] = {0x416B, 0xC0D6, 0x77EE, 0xC0D6, 0x77EE, 0xF431, 0x416B, 0xF431, 0x416B, 0xC0D6};
+const PROGMEM uint16_t e_pos[] = {0xE04E, 0x5E7B, 0xE94C, 0x5E7B, 0xE94C, 0x7E74, 0xEDCB, 0x7E74, 0xE4CD, 0x8E70, 0xDBCF, 0x7E74, 0xE04E, 0x7E74, 0xE04E, 0x5E7B};
+const PROGMEM uint16_t e_neg[] = {0xE04E, 0x4E7F, 0xE94C, 0x4E7F, 0xE94C, 0x2E87, 0xEDCB, 0x2E87, 0xE4CD, 0x1E8A, 0xDBCF, 0x2E87, 0xE04E, 0x2E87, 0xE04E, 0x4E7F};
+const PROGMEM uint16_t home_e[] = {0xD705, 0x3885, 0xC775, 0x53FB, 0xCB59, 0x53FB, 0xCB59, 0x6F71, 0xD321, 0x6F71, 0xD321, 0x61B6, 0xDAE9, 0x61B6, 0xDAE9, 0x6F71, 0xE2B1, 0x6F71, 0xE2B1, 0x53FB, 0xE695, 0x53FB, 0xE092, 0x495F, 0xE092, 0x3C0E, 0xDCAE, 0x3C0E, 0xDCAE, 0x4281};
+const PROGMEM uint16_t fine_label[] = {0x0D92, 0x9444, 0x5211, 0x9444, 0x5211, 0xA9EA, 0x0D92, 0xA9EA};
+const PROGMEM uint16_t fine_toggle[] = {0x56E7, 0x9444, 0x8007, 0x9444, 0x8007, 0xA9EA, 0x56E7, 0xA9EA};
+const PROGMEM uint16_t h1_temp[] = {0x9C2B, 0xDD3B, 0xBBDE, 0xDD3B, 0xBBDE, 0xFA57, 0x9C2B, 0xFA57};
+const PROGMEM uint16_t h1_label[] = {0x9C2B, 0xBE8F, 0xBBDC, 0xBE8F, 0xBBDC, 0xDBAA, 0x9C2B, 0xDBAA};
+const PROGMEM uint16_t h0_temp[] = {0x7BD0, 0xDD3B, 0x9B83, 0xDD3B, 0x9B83, 0xFA57, 0x7BD0, 0xFA57};
+const PROGMEM uint16_t h0_label[] = {0x7BD0, 0xBE8F, 0x9B83, 0xBE8F, 0x9B83, 0xDBAA, 0x7BD0, 0xDBAA};
+const PROGMEM uint16_t h2_temp[] = {0xBC86, 0xDD3B, 0xDC39, 0xDD3B, 0xDC39, 0xFA57, 0xBC86, 0xFA57};
+const PROGMEM uint16_t h2_label[] = {0xBC86, 0xBE8F, 0xDC37, 0xBE8F, 0xDC37, 0xDBAA, 0xBC86, 0xDBAA};
+const PROGMEM uint16_t h3_temp[] = {0xDCE2, 0xDD0D, 0xFC95, 0xDD0D, 0xFC95, 0xFA28, 0xDCE2, 0xFA28};
+const PROGMEM uint16_t h3_label[] = {0xDCE2, 0xBE60, 0xFC92, 0xBE60, 0xFC92, 0xDB7C, 0xDCE2, 0xDB7C};
+const PROGMEM uint16_t actual_temp[] = {0xCDF6, 0xD037, 0xF7CA, 0xD037, 0xF7CA, 0xF424, 0xCDF6, 0xF424};
+const PROGMEM uint16_t bed_icon[] = {0xCDF6, 0xA5CC, 0xF7CA, 0xA5CC, 0xF7CA, 0xC9B9, 0xCDF6, 0xC9B9};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/ui_portrait.h b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/ui_portrait.h
new file mode 100644
index 0000000..7aaf62b
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/bioprinter/ui_portrait.h
@@ -0,0 +1,54 @@
+/*****************
+ * ui_portrait.h *
+ *****************/
+
+/****************************************************************************
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+#pragma once
+
+constexpr float x_min = 0.000000;
+constexpr float x_max = 272.000000;
+constexpr float y_min = 0.000000;
+constexpr float y_max = 480.000000;
+
+const PROGMEM uint16_t z_neg[] = {0xC9B1, 0x96B3, 0xD990, 0x96B3, 0xD990, 0xA8D0, 0xE17F, 0xA8D0, 0xD1A0, 0xB1DF, 0xC1C2, 0xA8D0, 0xC9B1, 0xA8D0, 0xC9B1, 0x96B3};
+const PROGMEM uint16_t z_pos[] = {0xC9B1, 0x8DA4, 0xD990, 0x8DA4, 0xD990, 0x7B86, 0xE17F, 0x7B86, 0xD1A0, 0x7277, 0xC1C2, 0x7B86, 0xC9B1, 0x7B86, 0xC9B1, 0x8DA4};
+const PROGMEM uint16_t y_neg[] = {0x5037, 0x9979, 0x6264, 0x9979, 0x5529, 0xA92A, 0x5E3F, 0xA92A, 0x4575, 0xB103, 0x39E6, 0xA92A, 0x42FC, 0xA92A, 0x5037, 0x9979};
+const PROGMEM uint16_t y_pos[] = {0x5D72, 0x89C7, 0x6F9F, 0x89C7, 0x7CDA, 0x7A15, 0x85F0, 0x7A15, 0x7A61, 0x723D, 0x6197, 0x7A15, 0x6AAD, 0x7A15, 0x5D72, 0x89C7};
+const PROGMEM uint16_t x_neg[] = {0x513D, 0x8DB3, 0x4AA0, 0x958C, 0x2647, 0x958C, 0x22F8, 0x9979, 0x1769, 0x91A0, 0x3033, 0x89C7, 0x2CE4, 0x8DB3, 0x513D, 0x8DB3};
+const PROGMEM uint16_t x_pos[] = {0x7566, 0x8DB3, 0x6EC9, 0x958C, 0x9322, 0x958C, 0x8FD4, 0x9979, 0xA89E, 0x91A0, 0x9D0E, 0x89C7, 0x99C0, 0x8DB3, 0x7566, 0x8DB3};
+const PROGMEM uint16_t syringe_fluid[] = {0x7D1D, 0x4A0F, 0x87FC, 0x4C0E, 0x8CF4, 0x4C0E, 0x9801, 0x4A0F, 0x9801, 0x1AA2, 0x7D1D, 0x1AA2, 0x7D1D, 0x4A0F};
+const PROGMEM uint16_t syringe[] = {0x83C2, 0x42AA, 0x83C2, 0x43FF, 0x8D2C, 0x43FF, 0x8D2C, 0x42AA, 0xFFFF, 0x83C2, 0x3D54, 0x83C2, 0x3EAA, 0x8D2C, 0x3EAA, 0x8D2C, 0x3D54, 0xFFFF, 0x83C2, 0x37FF, 0x83C2, 0x3954, 0x8D2C, 0x3954, 0x8D2C, 0x37FF, 0xFFFF, 0x83C2, 0x32AA, 0x83C2, 0x33FF, 0x8D2C, 0x33FF, 0x8D2C, 0x32AA, 0xFFFF, 0x83C2, 0x2D54, 0x83C2, 0x2EAA, 0x8D2C, 0x2EAA, 0x8D2C, 0x2D54, 0xFFFF, 0x83C2, 0x27FF, 0x83C2, 0x2955, 0x8D2C, 0x2955, 0x8D2C, 0x27FF, 0xFFFF, 0x83C2, 0x22AA, 0x83C2, 0x23FF, 0x8D2C, 0x23FF, 0x8D2C, 0x22AA, 0xFFFF, 0x7AC7, 0x0F4B, 0x7AC7, 0x134A, 0x855B, 0x134A, 0x855B, 0x1949, 0x7AC7, 0x1949, 0x7AC7, 0x4B40, 0x855B, 0x4D40, 0x855B, 0x533F, 0x88E2, 0x533F, 0x88E2, 0x653C, 0x8C69, 0x673C, 0x8C69, 0x533F, 0x8FF0, 0x533F, 0x8FF0, 0x4D40, 0x9A85, 0x4B40, 0x9A85, 0x1949, 0x8FF0, 0x1949, 0x8FF0, 0x134A, 0x9A85, 0x134A, 0x9A85, 0x0F4B, 0xFFFF, 0x88E2, 0x134A, 0x8C69, 0x134A, 0x8C69, 0x1949, 0x88E2, 0x1949, 0x88E2, 0x134A, 0xFFFF, 0x7E4D, 0x1B49, 0x96FE, 0x1B49, 0x96FE, 0x4941, 0x8C69, 0x4B40, 0x88E2, 0x4B40, 0x7E4D, 0x4941, 0x7E4D, 0x1B49};
+const PROGMEM uint16_t syringe_outline[] = {0x7AC7, 0x0F4B, 0x7AC7, 0x134A, 0x855B, 0x134A, 0x855B, 0x1949, 0x7AC7, 0x1949, 0x7AC7, 0x4B40, 0x855B, 0x4D40, 0x855B, 0x533F, 0x88E2, 0x533F, 0x88E2, 0x653C, 0x8C69, 0x673C, 0x8C69, 0x533F, 0x8FF0, 0x533F, 0x8FF0, 0x4D40, 0x9A85, 0x4B40, 0x9A85, 0x1949, 0x8FF0, 0x1949, 0x8FF0, 0x134A, 0x9A85, 0x134A, 0x9A85, 0x0F4B, 0x7AC7, 0x0F4B};
+const PROGMEM uint16_t padlock[] = {0x645A, 0x8017, 0x5F9E, 0x80A1, 0x5BBA, 0x821B, 0x5911, 0x844A, 0x580A, 0x86F7, 0x580A, 0x8931, 0x5970, 0x8A98, 0x5C49, 0x8A98, 0x5DB0, 0x8931, 0x5DB0, 0x8703, 0x5E3C, 0x858E, 0x5FAA, 0x845F, 0x61C5, 0x8394, 0x645A, 0x834A, 0x66F0, 0x8394, 0x690C, 0x845F, 0x6A7A, 0x858D, 0x6B07, 0x8703, 0x6B07, 0x8F23, 0x57C8, 0x8F23, 0x551E, 0x8FC3, 0x5404, 0x9145, 0x5404, 0x9C8F, 0x551E, 0x9E11, 0x57C8, 0x9EB1, 0x70EE, 0x9EB1, 0x7398, 0x9E11, 0x74B2, 0x9C8F, 0x74B2, 0x9145, 0x7398, 0x8FC3, 0x70EE, 0x8F23, 0x70AC, 0x86FA, 0x6FA5, 0x844A, 0x6CFD, 0x821B, 0x6917, 0x80A1};
+const PROGMEM uint16_t home_z[] = {0xD6C9, 0x80CC, 0xBB53, 0x905B, 0xC231, 0x905B, 0xC231, 0x9FEB, 0xCFEC, 0x9FEB, 0xCFEC, 0x9823, 0xDDA7, 0x9823, 0xDDA7, 0x9FEB, 0xEB62, 0x9FEB, 0xEB62, 0x905B, 0xF240, 0x905B, 0xE7A3, 0x8A58, 0xE7A3, 0x82CD, 0xE0C6, 0x82CD, 0xE0C6, 0x8674};
+const PROGMEM uint16_t home_e[] = {0xB94F, 0x25AA, 0x9DD8, 0x353A, 0xA4B6, 0x353A, 0xA4B6, 0x44C9, 0xB271, 0x44C9, 0xB271, 0x3D02, 0xC02C, 0x3D02, 0xC02C, 0x44C9, 0xCDE7, 0x44C9, 0xCDE7, 0x353A, 0xD4C5, 0x353A, 0xCA28, 0x2F36, 0xCA28, 0x27AB, 0xC34B, 0x27AB, 0xC34B, 0x2B53};
+const PROGMEM uint16_t bed_icon[] = {0x1764, 0x2C4C, 0x6135, 0x2C4C, 0x6135, 0x40A8, 0x1764, 0x40A8};
+const PROGMEM uint16_t actual_temp[] = {0x1764, 0x466F, 0x6135, 0x466F, 0x6135, 0x5ACB, 0x1764, 0x5ACB};
+const PROGMEM uint16_t target_temp[] = {0x1764, 0x1228, 0x6135, 0x1228, 0x6135, 0x2684, 0x1764, 0x2684};
+const PROGMEM uint16_t fine_label[] = {0x1AA7, 0xC6D2, 0x9387, 0xC6D2, 0x9387, 0xD316, 0x1AA7, 0xD316};
+const PROGMEM uint16_t fine_toggle[] = {0x9C10, 0xC6D2, 0xE4A3, 0xC6D2, 0xE4A3, 0xD316, 0x9C10, 0xD316};
+const PROGMEM uint16_t usb_btn[] = {0x0B68, 0xE880, 0x7B1A, 0xE880, 0x7B1A, 0xF94B, 0x0B68, 0xF94B, 0x0B68, 0xE880};
+const PROGMEM uint16_t menu_btn[] = {0x84E3, 0xE880, 0xF495, 0xE880, 0xF495, 0xF94B, 0x84E3, 0xF94B, 0x84E3, 0xE880};
+const PROGMEM uint16_t e_pos[] = {0xC9B1, 0x3B2D, 0xD990, 0x3B2D, 0xD990, 0x4D4B, 0xE17F, 0x4D4B, 0xD1A0, 0x565A, 0xC1C2, 0x4D4B, 0xC9B1, 0x4D4B, 0xC9B1, 0x3B2D};
+const PROGMEM uint16_t e_neg[] = {0xC9B1, 0x321E, 0xD990, 0x321E, 0xD990, 0x2000, 0xE17F, 0x2000, 0xD1A0, 0x16F1, 0xC1C2, 0x2000, 0xC9B1, 0x2000, 0xC9B1, 0x321E};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/advanced_settings_menu.cpp b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/advanced_settings_menu.cpp
new file mode 100644
index 0000000..00cdf76
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/advanced_settings_menu.cpp
@@ -0,0 +1,95 @@
+/*****************************************
+ * cocoa_press/advance_settings_menu.cpp *
+ *****************************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef COCOA_ADVANCED_SETTINGS_MENU
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define GRID_COLS 3
+#define GRID_ROWS 4
+#define STEPS_PER_MM_POS BTN_POS(1,1), BTN_SIZE(1,1)
+#define TMC_CURRENT_POS BTN_POS(2,1), BTN_SIZE(1,1)
+#define LIN_ADVANCE_POS BTN_POS(3,1), BTN_SIZE(1,1)
+#define VELOCITY_POS BTN_POS(1,2), BTN_SIZE(1,1)
+#define ACCELERATION_POS BTN_POS(2,2), BTN_SIZE(1,1)
+#define JERK_POS BTN_POS(3,2), BTN_SIZE(1,1)
+#define DISPLAY_POS BTN_POS(1,3), BTN_SIZE(1,1)
+#define INTERFACE_POS BTN_POS(2,3), BTN_SIZE(1,1)
+#define ENDSTOPS_POS BTN_POS(3,3), BTN_SIZE(1,1)
+#define RESTORE_DEFAULTS_POS BTN_POS(1,4), BTN_SIZE(2,1)
+#define BACK_POS BTN_POS(3,4), BTN_SIZE(1,1)
+
+void AdvancedSettingsMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true));
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+ .tag(2) .button(STEPS_PER_MM_POS, GET_TEXT_F(MSG_STEPS_PER_MM))
+ .enabled(ENABLED(HAS_TRINAMIC_CONFIG))
+ .tag(3) .button(TMC_CURRENT_POS, GET_TEXT_F(MSG_TMC_CURRENT))
+ .enabled(ENABLED(LIN_ADVANCE))
+ .tag(4) .button(LIN_ADVANCE_POS, GET_TEXT_F(MSG_LINEAR_ADVANCE))
+ .tag(5) .button(VELOCITY_POS, GET_TEXT_F(MSG_MAX_SPEED))
+ .tag(6) .button(ACCELERATION_POS, GET_TEXT_F(MSG_ACCELERATION))
+ .tag(7) .button(JERK_POS, GET_TEXT_F(TERN(HAS_JUNCTION_DEVIATION, MSG_JUNCTION_DEVIATION, MSG_JERK)))
+ .tag(8) .button(ENDSTOPS_POS, GET_TEXT_F(MSG_LCD_ENDSTOPS))
+ .tag(9) .button(INTERFACE_POS, GET_TEXT_F(MSG_INTERFACE))
+ .tag(10).button(DISPLAY_POS, GET_TEXT_F(MSG_DISPLAY_MENU))
+ .tag(11).button(RESTORE_DEFAULTS_POS, GET_TEXT_F(MSG_RESTORE_DEFAULTS))
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BUTTON_DONE));
+ }
+}
+
+bool AdvancedSettingsMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ case 2: GOTO_SCREEN(StepsScreen); break;
+ #if HAS_TRINAMIC_CONFIG
+ case 3: GOTO_SCREEN(StepperCurrentScreen); break;
+ #endif
+ #if ENABLED(LIN_ADVANCE)
+ case 4: GOTO_SCREEN(LinearAdvanceScreen); break;
+ #endif
+ case 5: GOTO_SCREEN(MaxVelocityScreen); break;
+ case 6: GOTO_SCREEN(DefaultAccelerationScreen); break;
+ case 7: GOTO_SCREEN(TERN(HAS_JUNCTION_DEVIATION, JunctionDeviationScreen, JerkScreen)); break;
+ case 8: GOTO_SCREEN(EndstopStatesScreen); break;
+ case 9: GOTO_SCREEN(InterfaceSettingsScreen); LockScreen::check_passcode(); break;
+ case 10: GOTO_SCREEN(DisplayTuningScreen); break;
+ case 11: GOTO_SCREEN(RestoreFailsafeDialogBox); LockScreen::check_passcode(); break;
+ default: return false;
+ }
+ return true;
+}
+#endif // COCOA_ADVANCED_SETTINGS_MENU
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/advanced_settings_menu.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/advanced_settings_menu.h
new file mode 100644
index 0000000..02f6557
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/advanced_settings_menu.h
@@ -0,0 +1,32 @@
+/***************************************
+ * cocoa_press/advance_settings_menu.h *
+ ***************************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define COCOA_ADVANCED_SETTINGS_MENU
+#define COCOA_ADVANCED_SETTINGS_MENU_CLASS AdvancedSettingsMenu
+
+class AdvancedSettingsMenu : public BaseScreen, public CachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/cocoa_press_ui.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/cocoa_press_ui.h
new file mode 100644
index 0000000..6a02228
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/cocoa_press_ui.h
@@ -0,0 +1,60 @@
+
+/****************************************************************************
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+#pragma once
+
+constexpr float x_min = 0.000000;
+constexpr float x_max = 480.000000;
+constexpr float y_min = 0.000000;
+constexpr float y_max = 272.000000;
+
+const PROGMEM uint16_t syringe_outline[] = {0xED96, 0x14F0, 0xE65D, 0x10E9, 0xDED2, 0x0F9C, 0xD74B, 0x110E, 0xD01B, 0x1543, 0xCE80, 0x1836, 0xCE0A, 0x1C3A, 0xCE0F, 0x27AD, 0xCF0A, 0x2BD3, 0xD127, 0x2E5B, 0xD2A1, 0x2FF0, 0xD2A2, 0x9FC9, 0xD407, 0xA97A, 0xD7B9, 0xB10C, 0xD7BF, 0xBB58, 0xD978, 0xC2BE, 0xDD55, 0xC6EB, 0xDD58, 0xD159, 0xDE3B, 0xD3A8, 0xDFCF, 0xD3AF, 0xE0B8, 0xD04C, 0xE0B8, 0xC6EB, 0xE4A7, 0xC299, 0xE652, 0xBAF6, 0xE652, 0xB10C, 0xEA2E, 0xA8EA, 0xEB6C, 0x9E86, 0xEB6C, 0x2F58, 0xEF3C, 0x2B4E, 0xF003, 0x2583, 0xEFFD, 0x1AC2, 0xED96, 0x14F0, 0xED96, 0x14F0};
+const PROGMEM uint16_t syringe_fluid[] = {0xDE73, 0x2512, 0xDA0C, 0x261D, 0xD5B8, 0x29A0, 0xD4AE, 0x2D87, 0xD4AE, 0x9F60, 0xD585, 0xA63B, 0xDE44, 0xA9DE, 0xE32A, 0xA942, 0xE7E3, 0xA6A5, 0xE930, 0xA342, 0xE95D, 0x9C1D, 0xE95B, 0x31B8, 0xE955, 0x2B63, 0xE867, 0x2A67, 0xE790, 0x28DE, 0xE342, 0x25CB, 0xDE73, 0x2512};
+const PROGMEM uint16_t syringe[] = {0xED91, 0x1502, 0xE658, 0x10FB, 0xDECE, 0x0FAE, 0xD746, 0x1120, 0xD016, 0x1555, 0xCE7B, 0x1848, 0xCE05, 0x1C4D, 0xCE0A, 0x27BF, 0xCF05, 0x2BE5, 0xD122, 0x2E6E, 0xD29C, 0x3002, 0xD29D, 0x9FDB, 0xD402, 0xA98C, 0xD7B4, 0xB11F, 0xD7BA, 0xBB6A, 0xD973, 0xC2D1, 0xDD50, 0xC6FD, 0xDD53, 0xD16C, 0xDE36, 0xD3BA, 0xDFCA, 0xD3C2, 0xE0B3, 0xD05E, 0xE0B3, 0xC6FD, 0xE4A2, 0xC2AB, 0xE64D, 0xBB09, 0xE64D, 0xB11F, 0xEA29, 0xA8FC, 0xEB67, 0x9E98, 0xEB67, 0x2F6B, 0xEF37, 0x2B60, 0xEFFE, 0x2595, 0xEFF8, 0x1AD5, 0xED91, 0x1502, 0xED91, 0x1502, 0xFFFF, 0xD1CF, 0x1A7E, 0xD84F, 0x16DB, 0xDF19, 0x15A9, 0xE5E0, 0x16EA, 0xEC5B, 0x1AA4, 0xEC9D, 0x1D34, 0xEC9D, 0x20CC, 0xE5F1, 0x1D41, 0xDF02, 0x1C12, 0xD812, 0x1D41, 0xD166, 0x20CC, 0xD16C, 0x1B45, 0xD1CF, 0x1A7E, 0xFFFF, 0xE3BD, 0xACFD, 0xDE8E, 0xAF4F, 0xD988, 0xAC0F, 0xD7CC, 0xA8CD, 0xDD1C, 0xAAA9, 0xE287, 0xAA5B, 0xE655, 0xA8BE, 0xE3BD, 0xACFD, 0xFFFF, 0xE802, 0x2DC5, 0xE809, 0x343C, 0xE808, 0x9FC8, 0xE7E3, 0xA296, 0xE70D, 0xA4B1, 0xE2C9, 0xA70E, 0xDE4E, 0xA790, 0xD6A1, 0xA457, 0xD5FF, 0x9F2B, 0xD5FF, 0x2DFD, 0xD6B2, 0x2B72, 0xDA78, 0x2861, 0xDE9D, 0x276F, 0xE300, 0x2824, 0xE70D, 0x2B13, 0xE7FF, 0x2DB6, 0xE800, 0x2DC5, 0xE802, 0x2DC5, 0xFFFF, 0xE2ED, 0xBA8B, 0xE1CC, 0xBF52, 0xDF1C, 0xC165, 0xDC64, 0xBF99, 0xDB1B, 0xBAFF, 0xDB19, 0xB433, 0xDF04, 0xB552, 0xE2EF, 0xB438, 0xE2ED, 0xBA8B, 0xFFFF, 0xEC09, 0x2893, 0xE925, 0x2A08, 0xE57D, 0x261D, 0xE149, 0x246F, 0xDBDE, 0x24A0, 0xD6BC, 0x2795, 0xD484, 0x2A46, 0xD1C0, 0x2853, 0xD166, 0x251E, 0xD80D, 0x2151, 0xDF02, 0x200C, 0xE5F6, 0x2151, 0xEC9D, 0x251E, 0xEC09, 0x2893};
+const PROGMEM uint16_t park_btn[] = {0x0AAA, 0x0E1E, 0x57FF, 0x0E1E, 0x57FF, 0x33C3, 0x0AAA, 0x33C3, 0x0AAA, 0x0E1E};
+const PROGMEM uint16_t pause_btn[] = {0x47FF, 0xCA58, 0x7FFF, 0xCA58, 0x7FFF, 0xEFFE, 0x47FF, 0xEFFE, 0x47FF, 0xCA58};
+const PROGMEM uint16_t load_chocolate_btn[] = {0x0AAA, 0x3D2C, 0x57FF, 0x3D2C, 0x57FF, 0x62D2, 0x0AAA, 0x62D2, 0x0AAA, 0x3D2C};
+const PROGMEM uint16_t preheat_chocolate_btn[] = {0x0AAA, 0x6C3B, 0x57FF, 0x6C3B, 0x57FF, 0x91E0, 0x0AAA, 0x91E0, 0x0AAA, 0x6C3B};
+const PROGMEM uint16_t menu_btn[] = {0x0AAA, 0x9B4A, 0x57FF, 0x9B4A, 0x57FF, 0xC0EF, 0x0AAA, 0xC0EF, 0x0AAA, 0x9B4A};
+const PROGMEM uint16_t print_btn[] = {0x0AAA, 0xCA58, 0x42AA, 0xCA58, 0x42AA, 0xEFFE, 0x0AAA, 0xEFFE, 0x0AAA, 0xCA58};
+const PROGMEM uint16_t stop_btn[] = {0x8554, 0xCA58, 0xBD53, 0xCA58, 0xBD53, 0xEFFE, 0x8554, 0xEFFE, 0x8554, 0xCA58};
+const PROGMEM uint16_t print_time_hms[] = {0x62A9, 0xA968, 0x8FFE, 0xA968, 0x8FFE, 0xC0EF, 0x62A9, 0xC0EF, 0x62A9, 0xA968};
+const PROGMEM uint16_t print_time_percent[] = {0x8FFE, 0xA968, 0xBD53, 0xA968, 0xBD53, 0xC0EF, 0x8FFE, 0xC0EF, 0x8FFE, 0xA968};
+const PROGMEM uint16_t print_time_label[] = {0x62A9, 0x91E0, 0xBD53, 0x91E0, 0xBD53, 0xA986, 0x62A9, 0xA986, 0x62A9, 0x91E0};
+const PROGMEM uint16_t h3_temp[] = {0x62A9, 0x75A4, 0x8FFE, 0x75A4, 0x8FFE, 0x8D2C, 0x62A9, 0x8D2C, 0x62A9, 0x75A4};
+const PROGMEM uint16_t h3_label[] = {0x62A9, 0x5E1D, 0x8FFE, 0x5E1D, 0x8FFE, 0x75A4, 0x62A9, 0x75A4, 0x62A9, 0x5E1D};
+const PROGMEM uint16_t chocolate_label[] = {0x62A9, 0x12D2, 0xBD53, 0x12D2, 0xBD53, 0x2A5A, 0x62A9, 0x2A5A, 0x62A9, 0x12D2};
+const PROGMEM uint16_t h0_label[] = {0x62A9, 0x2A5A, 0x8FFE, 0x2A5A, 0x8FFE, 0x41E1, 0x62A9, 0x41E1, 0x62A9, 0x2A5A};
+const PROGMEM uint16_t h0_temp[] = {0x62A9, 0x41E1, 0x8FFE, 0x41E1, 0x8FFE, 0x5968, 0x62A9, 0x5968, 0x62A9, 0x41E1};
+const PROGMEM uint16_t h1_label[] = {0x8FFE, 0x2A5A, 0xBD53, 0x2A5A, 0xBD53, 0x41E1, 0x8FFE, 0x41E1, 0x8FFE, 0x2A5A};
+const PROGMEM uint16_t h1_temp[] = {0x8FFE, 0x41E1, 0xBD53, 0x41E1, 0xBD53, 0x5968, 0x8FFE, 0x5968, 0x8FFE, 0x41E1};
+const PROGMEM uint16_t h2_label[] = {0x8FFE, 0x5E1D, 0xBD53, 0x5E1D, 0xBD53, 0x75A4, 0x8FFE, 0x75A4, 0x8FFE, 0x5E1D};
+const PROGMEM uint16_t h2_temp[] = {0x8FFE, 0x75A4, 0xBD53, 0x75A4, 0xBD53, 0x8D2C, 0x8FFE, 0x8D2C, 0x8FFE, 0x75A4};
+const PROGMEM uint16_t extrude_btn[] = {0xC859, 0xDD2B, 0xF5AE, 0xDD2B, 0xF5AE, 0xEFFE, 0xC859, 0xEFFE, 0xC859, 0xDD2B};
+const PROGMEM uint16_t load_screen_extrude[] = {0x25FB, 0x89AE, 0x2F58, 0x89AE, 0x2F58, 0xAAF6, 0x3406, 0xAAF6, 0x2AAA, 0xBB9A, 0x214D, 0xAAF6, 0x25FB, 0xAAF6, 0x25FB, 0x89AE};
+const PROGMEM uint16_t load_screen_retract[] = {0x25FC, 0x790A, 0x2F58, 0x790A, 0x2F58, 0x57C2, 0x3406, 0x57C2, 0x2AAA, 0x471D, 0x214D, 0x57C2, 0x25FC, 0x57C2, 0x25FC, 0x790A};
+const PROGMEM uint16_t load_screen_back_btn[] = {0x1555, 0xCA58, 0xC553, 0xCA58, 0xC553, 0xEFFE, 0x1555, 0xEFFE, 0x1555, 0xCA58};
+const PROGMEM uint16_t load_screen_unload_btn[] = {0x4AAA, 0x8EBD, 0xC553, 0x8EBD, 0xC553, 0xB463, 0x4AAA, 0xB463, 0x4AAA, 0x8EBD};
+const PROGMEM uint16_t load_screen_load_btn[] = {0x4AAA, 0x5322, 0xC553, 0x5322, 0xC553, 0x78C7, 0x4AAA, 0x78C7, 0x4AAA, 0x5322};
+const PROGMEM uint16_t load_sreen_title[] = {0x4AAA, 0x1787, 0xC553, 0x1787, 0xC553, 0x3D2C, 0x4AAA, 0x3D2C, 0x4AAA, 0x1787};
+const PROGMEM uint16_t load_screen_increment[] = {0x1555, 0x2E1D, 0x3FFF, 0x2E1D, 0x3FFF, 0x3D2C, 0x1555, 0x3D2C, 0x1555, 0x2E1D};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/leveling_menu.cpp b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/leveling_menu.cpp
new file mode 100644
index 0000000..5e61bdb
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/leveling_menu.cpp
@@ -0,0 +1,91 @@
+/*********************************
+ * cocoa_press/leveling_menu.cpp *
+ *********************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#if ENABLED(COCOA_LEVELING_MENU)
+
+#if BOTH(HAS_BED_PROBE, BLTOUCH)
+ #include "../../../../feature/bltouch.h"
+#endif
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define GRID_COLS 3
+#define GRID_ROWS 5
+#define BED_MESH_TITLE_POS BTN_POS(1,1), BTN_SIZE(3,1)
+#define PROBE_BED_POS BTN_POS(1,2), BTN_SIZE(1,1)
+#define SHOW_MESH_POS BTN_POS(2,2), BTN_SIZE(1,1)
+#define EDIT_MESH_POS BTN_POS(3,2), BTN_SIZE(1,1)
+#define BLTOUCH_TITLE_POS BTN_POS(1,3), BTN_SIZE(3,1)
+#define BLTOUCH_RESET_POS BTN_POS(1,4), BTN_SIZE(1,1)
+#define BLTOUCH_TEST_POS BTN_POS(2,4), BTN_SIZE(1,1)
+#define BACK_POS BTN_POS(1,5), BTN_SIZE(3,1)
+
+void LevelingMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.font(font_large)
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .text(BED_MESH_TITLE_POS, GET_TEXT_F(MSG_BED_LEVELING))
+ .text(BLTOUCH_TITLE_POS, GET_TEXT_F(MSG_BLTOUCH))
+ .font(font_medium).colors(normal_btn)
+ .tag(2).button(PROBE_BED_POS, GET_TEXT_F(MSG_PROBE_BED))
+ .enabled(ENABLED(HAS_MESH))
+ .tag(3).button(SHOW_MESH_POS, GET_TEXT_F(MSG_MESH_VIEW))
+ .enabled(ENABLED(HAS_MESH))
+ .tag(4).button(EDIT_MESH_POS, GET_TEXT_F(MSG_EDIT_MESH))
+ #undef GRID_COLS
+ #define GRID_COLS 2
+ .tag(5).button(BLTOUCH_RESET_POS, GET_TEXT_F(MSG_BLTOUCH_RESET))
+ .tag(6).button(BLTOUCH_TEST_POS, GET_TEXT_F(MSG_BLTOUCH_SELFTEST))
+ #undef GRID_COLS
+ #define GRID_COLS 3
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BUTTON_DONE));
+ }
+}
+
+bool LevelingMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ case 2: BedMeshViewScreen::doProbe(); break;
+ case 3: BedMeshViewScreen::show(); break;
+ case 4: BedMeshEditScreen::show(); break;
+ case 5: injectCommands(F("M280 P0 S60")); break;
+ case 6: SpinnerDialogBox::enqueueAndWait(F("M280 P0 S90\nG4 P100\nM280 P0 S120")); break;
+ default: return false;
+ }
+ return true;
+}
+
+#endif // COCOA_LEVELING_MENU
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/leveling_menu.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/leveling_menu.h
new file mode 100644
index 0000000..8275380
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/leveling_menu.h
@@ -0,0 +1,32 @@
+/*******************************
+ * cocoa_press/leveling_menu.h *
+ ******************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define COCOA_LEVELING_MENU
+#define COCOA_LEVELING_MENU_CLASS LevelingMenu
+
+class LevelingMenu : public BaseScreen, public CachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.cpp b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.cpp
new file mode 100644
index 0000000..d40b3be
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.cpp
@@ -0,0 +1,218 @@
+/**********************************
+ * cocoa_press/load_chocolate.cpp *
+ **********************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2020 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+#include "../screen_data.h"
+
+#ifdef COCOA_LOAD_CHOCOLATE_SCREEN
+
+#include "cocoa_press_ui.h"
+
+#define POLY(A) PolyUI::poly_reader_t(A, sizeof(A)/sizeof(A[0]))
+
+const uint8_t shadow_depth = 5;
+
+using namespace ExtUI;
+using namespace FTDI;
+using namespace Theme;
+
+constexpr static LoadChocolateScreenData &mydata = screen_data.LoadChocolateScreen;
+
+void LoadChocolateScreen::draw_syringe(draw_mode_t what) {
+ #if ENABLED(COCOA_PRESS_CHOCOLATE_LEVEL_SENSOR)
+ const float fill_level = get_chocolate_fill_level();
+ #else
+ constexpr float fill_level = 1.0f;
+ #endif
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ if (what & BACKGROUND) {
+ // Paint the shadow for the syringe
+ ui.color(shadow_rgb);
+ ui.shadow(POLY(syringe_outline), shadow_depth);
+ }
+
+ if (what & FOREGROUND) {
+ int16_t x, y, h, v;
+
+ // Paint the syringe icon
+ ui.color(syringe_rgb);
+ ui.fill(POLY(syringe_outline));
+
+ ui.color(fluid_rgb);
+ ui.bounds(POLY(syringe_fluid), x, y, h, v);
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(SCISSOR_XY(x,y + v * (1.0 - fill_level)));
+ cmd.cmd(SCISSOR_SIZE(h, v * fill_level));
+ ui.fill(POLY(syringe_fluid), false);
+ cmd.cmd(RESTORE_CONTEXT());
+
+ ui.color(stroke_rgb);
+ ui.fill(POLY(syringe));
+ }
+}
+
+void LoadChocolateScreen::draw_buttons(draw_mode_t what) {
+ int16_t x, y, h, v;
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ cmd.font(font_medium).colors(normal_btn);
+
+ ui.bounds(POLY(load_screen_unload_btn), x, y, h, v);
+ cmd.tag(2).button(x, y, h, v, GET_TEXT_F(MSG_FULL_UNLOAD));
+
+ ui.bounds(POLY(load_screen_load_btn), x, y, h, v);
+ cmd.tag(3).button(x, y, h, v, GET_TEXT_F(MSG_FULL_LOAD));
+
+ ui.bounds(POLY(load_screen_back_btn), x, y, h, v);
+ cmd.tag(1).colors(action_btn).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_DONE));
+}
+
+void LoadChocolateScreen::draw_text(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ int16_t x, y, h, v;
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ cmd.font(font_medium).cmd(COLOR_RGB(bg_text_enabled));
+
+ ui.bounds(POLY(load_sreen_title), x, y, h, v);
+ cmd.tag(2).text(x, y, h, v, GET_TEXT_F(MSG_LOAD_UNLOAD));
+
+ ui.bounds(POLY(load_screen_increment), x, y, h, v);
+ cmd.tag(3).text(x, y, h, v, GET_TEXT_F(MSG_INCREMENT));
+ }
+}
+
+void LoadChocolateScreen::draw_arrows(draw_mode_t what) {
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ ui.button_fill (fill_rgb);
+ ui.button_stroke(stroke_rgb, 28);
+ ui.button_shadow(shadow_rgb, shadow_depth);
+
+ constexpr uint8_t style = PolyUI::REGULAR;
+
+ ui.button(4, POLY(load_screen_extrude), style);
+ ui.button(5, POLY(load_screen_retract), style);
+}
+
+void LoadChocolateScreen::onEntry() {
+ mydata.repeat_tag = 0;
+}
+
+void LoadChocolateScreen::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ draw_syringe(what);
+ draw_arrows(what);
+ draw_buttons(what);
+ draw_text(what);
+}
+
+bool LoadChocolateScreen::onTouchStart(uint8_t) {
+ mydata.repeat_tag = 0;
+ return true;
+}
+
+bool LoadChocolateScreen::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+ switch (tag) {
+ case 2:
+ mydata.repeat_tag = (mydata.repeat_tag == 2) ? 0 : 2;
+ break;
+ case 3:
+ mydata.repeat_tag = (mydata.repeat_tag == 3) ? 0 : 3;
+ break;
+ case 1: GOTO_PREVIOUS(); break;
+ }
+ return true;
+}
+
+void LoadChocolateScreen::setManualFeedrateAndIncrement(float feedrate_mm_s, float &increment_mm) {
+ // Compute increment so feedrate so that the tool lags the adjuster when it is
+ // being held down, this allows enough margin for the planner to
+ // connect segments and even out the motion.
+ ExtUI::setFeedrate_mm_s(feedrate_mm_s);
+ increment_mm = feedrate_mm_s / ((TOUCH_REPEATS_PER_SECOND) * 0.80f);
+}
+
+bool LoadChocolateScreen::onTouchHeld(uint8_t tag) {
+ if (ExtUI::isMoving()) return false; // Don't allow moves to accumulate
+ float increment;
+ setManualFeedrateAndIncrement(20, increment);
+ #define UI_INCREMENT_AXIS(axis) UI_INCREMENT(AxisPosition_mm, axis);
+ #define UI_DECREMENT_AXIS(axis) UI_DECREMENT(AxisPosition_mm, axis);
+ switch (tag) {
+ case 2: {
+ if (get_chocolate_fill_level() < 0.1) {
+ mydata.repeat_tag = 0;
+ return false;
+ }
+ UI_INCREMENT_AXIS(E0);
+ break;
+ }
+ case 3: {
+ if (get_chocolate_fill_level() > 0.75) {
+ mydata.repeat_tag = 0;
+ return false;
+ }
+ UI_DECREMENT_AXIS(E0);
+ break;
+ }
+ case 4:
+ UI_INCREMENT_AXIS(E0);
+ break;
+ case 5:
+ UI_DECREMENT_AXIS(E0);
+ break;
+ default: return false;
+ }
+ #undef UI_DECREMENT_AXIS
+ #undef UI_INCREMENT_AXIS
+ return false;
+}
+
+void LoadChocolateScreen::onIdle() {
+ reset_menu_timeout();
+ if (mydata.repeat_tag) onTouchHeld(mydata.repeat_tag);
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ if (!EventLoop::is_touch_held())
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+#endif // COCOA_LOAD_CHOCOLATE_SCREEN
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.h
new file mode 100644
index 0000000..4a582f0
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/load_chocolate.h
@@ -0,0 +1,47 @@
+/********************************
+ * cocoa_press/load_chocolate.h *
+ ********************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2020 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define COCOA_LOAD_CHOCOLATE_SCREEN
+#define COCOA_LOAD_CHOCOLATE_SCREEN_CLASS LoadChocolateScreen
+
+struct LoadChocolateScreenData {
+ uint8_t repeat_tag;
+};
+
+class LoadChocolateScreen : public BaseScreen, public CachedScreen {
+ private:
+ static void draw_syringe(draw_mode_t what);
+ static void draw_arrows(draw_mode_t what);
+ static void draw_buttons(draw_mode_t what);
+ static void draw_text(draw_mode_t what);
+ public:
+ static void setManualFeedrateAndIncrement(float feedrate_mm_s, float &increment);
+ static void onEntry();
+ static void onIdle();
+ static void onRedraw(draw_mode_t);
+ static bool onTouchStart(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+ static bool onTouchHeld(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/main_menu.cpp b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/main_menu.cpp
new file mode 100644
index 0000000..ee299a7
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/main_menu.cpp
@@ -0,0 +1,100 @@
+/*****************************
+ * cocoa_press/main_menu.cpp *
+ *****************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef COCOA_MAIN_MENU
+
+using namespace FTDI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 6
+
+#define ZPROBE_ZOFFSET_POS BTN_POS(1,1), BTN_SIZE(1,1)
+#define MOVE_XYZ_POS BTN_POS(1,2), BTN_SIZE(1,1)
+#define TEMPERATURE_POS BTN_POS(2,1), BTN_SIZE(1,1)
+#define MOVE_E_POS BTN_POS(2,2), BTN_SIZE(1,1)
+#define SPEED_POS BTN_POS(1,3), BTN_SIZE(1,1)
+#define FLOW_POS BTN_POS(2,3), BTN_SIZE(1,1)
+#define ADVANCED_SETTINGS_POS BTN_POS(1,4), BTN_SIZE(1,1)
+#define DISABLE_STEPPERS_POS BTN_POS(2,4), BTN_SIZE(1,1)
+#define LEVELING_POS BTN_POS(1,5), BTN_SIZE(1,1)
+#define ABOUT_PRINTER_POS BTN_POS(2,5), BTN_SIZE(1,1)
+#define BACK_POS BTN_POS(1,6), BTN_SIZE(2,1)
+
+void MainMenu::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true));
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(Theme::font_medium)
+ .tag( 2).button(MOVE_XYZ_POS, GET_TEXT_F(MSG_XYZ_MOVE))
+ .tag( 3).button(TEMPERATURE_POS, GET_TEXT_F(MSG_TEMPERATURE))
+ .enabled(BOTH(HAS_LEVELING, HAS_BED_PROBE))
+ .tag( 4).button(ZPROBE_ZOFFSET_POS, GET_TEXT_F(MSG_ZPROBE_ZOFFSET))
+ .tag( 5).button(MOVE_E_POS, GET_TEXT_F(MSG_E_MOVE))
+ .tag( 6).button(SPEED_POS, GET_TEXT_F(MSG_PRINT_SPEED))
+ .tag( 7).button(FLOW_POS, GET_TEXT_F(MSG_FLOW))
+ .tag( 8).button(ADVANCED_SETTINGS_POS, GET_TEXT_F(MSG_ADVANCED_SETTINGS))
+ .tag( 9).button(DISABLE_STEPPERS_POS, GET_TEXT_F(MSG_DISABLE_STEPPERS))
+ .enabled(ENABLED(HAS_LEVELING))
+ .tag(10).button(LEVELING_POS, GET_TEXT_F(MSG_LEVELING))
+ .tag(11).button(ABOUT_PRINTER_POS, GET_TEXT_F(MSG_INFO_MENU))
+ .colors(action_btn)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BUTTON_DONE));
+ }
+}
+
+bool MainMenu::onTouchEnd(uint8_t tag) {
+ using namespace ExtUI;
+
+ switch (tag) {
+ case 1: SaveSettingsDialogBox::promptToSaveSettings(); break;
+ case 2: GOTO_SCREEN(MoveXYZScreen); break;
+ case 3: GOTO_SCREEN(TemperatureScreen); break;
+ #if BOTH(HAS_LEVELING, HAS_BED_PROBE)
+ case 4: GOTO_SCREEN(ZOffsetScreen); break;
+ #endif
+ case 5: GOTO_SCREEN(MoveEScreen); break;
+ case 6: GOTO_SCREEN(FeedratePercentScreen); break;
+ case 7: GOTO_SCREEN(FlowPercentScreen); break;
+ case 8: GOTO_SCREEN(AdvancedSettingsMenu); break;
+ case 9: injectCommands(F("M84")); break;
+ #if HAS_LEVELING
+ case 10: GOTO_SCREEN(LevelingMenu); break;
+ #endif
+ case 11: GOTO_SCREEN(AboutScreen); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+#endif // COCOA_MAIN_MENU
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/main_menu.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/main_menu.h
new file mode 100644
index 0000000..460bb4b
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/main_menu.h
@@ -0,0 +1,33 @@
+/***************************
+ * cocoa_press/main_menu.h *
+ ***************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define COCOA_MAIN_MENU
+#define COCOA_MAIN_MENU_CLASS MainMenu
+
+class MainMenu : public BaseScreen, public CachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_e_screen.cpp b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_e_screen.cpp
new file mode 100644
index 0000000..f7dbc46
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_e_screen.cpp
@@ -0,0 +1,63 @@
+/*********************************
+ * cocoa_press/move_e_screen.cpp *
+ *********************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+#include "../screen_data.h"
+
+#ifdef COCOA_MOVE_E_SCREEN
+
+using namespace FTDI;
+using namespace ExtUI;
+
+constexpr static MoveAxisScreenData &mydata = screen_data.MoveAxisScreen;
+
+void MoveEScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(1, DEFAULT_MIDRANGE);
+ w.units(GET_TEXT_F(MSG_UNITS_MM));
+ w.heading( GET_TEXT_F(MSG_E_MOVE));
+ w.color(Theme::e_axis);
+ #if EXTRUDERS == 1
+ w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E), mydata.e_rel[0], canMove(E0));
+ #elif HAS_MULTI_EXTRUDER
+ w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E1), mydata.e_rel[0], canMove(E0));
+ w.adjuster( 10, GET_TEXT_F(MSG_AXIS_E2), mydata.e_rel[1], canMove(E1));
+ #if EXTRUDERS > 2
+ w.adjuster( 12, GET_TEXT_F(MSG_AXIS_E3), mydata.e_rel[2], canMove(E2));
+ #endif
+ #if EXTRUDERS > 3
+ w.adjuster( 14, GET_TEXT_F(MSG_AXIS_E4), mydata.e_rel[3], canMove(E3));
+ #endif
+ #endif
+ w.increments();
+}
+
+void MoveEScreen::onIdle() {
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+#endif // COCOA_MOVE_E_SCREEN
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_e_screen.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_e_screen.h
new file mode 100644
index 0000000..0cede6f
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_e_screen.h
@@ -0,0 +1,33 @@
+/*******************************
+ * cocoa_press/move_e_screen.h *
+ *******************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define COCOA_MOVE_E_SCREEN
+#define COCOA_MOVE_E_SCREEN_CLASS MoveEScreen
+
+class MoveEScreen : public BaseMoveAxisScreen, public CachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static void onIdle();
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_xyz_screen.cpp b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_xyz_screen.cpp
new file mode 100644
index 0000000..8e80bd5
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_xyz_screen.cpp
@@ -0,0 +1,52 @@
+/***********************************
+ * cocoa_press/move_xyz_screen.cpp *
+ ***********************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+#include "../screen_data.h"
+
+#ifdef COCOA_MOVE_XYZ_SCREEN
+
+using namespace FTDI;
+using namespace ExtUI;
+
+void MoveXYZScreen::onRedraw(draw_mode_t what) {
+ widgets_t w(what);
+ w.precision(1);
+ w.units(GET_TEXT_F(MSG_UNITS_MM));
+ w.heading( GET_TEXT_F(MSG_XYZ_MOVE));
+ w.home_buttons(20);
+ w.color(Theme::x_axis).adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisPosition_mm(X), canMove(X));
+ w.color(Theme::y_axis).adjuster( 4, GET_TEXT_F(MSG_AXIS_Y), getAxisPosition_mm(Y), canMove(Y));
+ w.color(Theme::z_axis).adjuster( 6, GET_TEXT_F(MSG_AXIS_Z), getAxisPosition_mm(Z), canMove(Z));
+ w.increments();
+}
+
+void MoveXYZScreen::onIdle() {
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+#endif // COCOA_MOVE_XYZ_SCREEN
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_xyz_screen.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_xyz_screen.h
new file mode 100644
index 0000000..015f5b3
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/move_xyz_screen.h
@@ -0,0 +1,33 @@
+/*********************************
+ * cocoa_press/move_xyz_screen.h *
+ *********************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define COCOA_MOVE_XYZ_SCREEN
+#define COCOA_MOVE_XYZ_SCREEN_CLASS MoveXYZScreen
+
+class MoveXYZScreen : public BaseMoveAxisScreen, public CachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static void onIdle();
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_menu.cpp b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_menu.cpp
new file mode 100644
index 0000000..b01aa81
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_menu.cpp
@@ -0,0 +1,116 @@
+/********************************
+ * cocoa_press/preheat_menu.cpp *
+ ********************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2020 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef COCOA_PREHEAT_MENU
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+#define GRID_COLS 2
+#define GRID_ROWS 5
+
+void PreheatMenu::onRedraw(draw_mode_t what) {
+ const int16_t w = TERN0(COCOA_PRESS_EXTRA_HEATER, has_extra_heater() ? BTN_W(1) : BTN_W(2));
+ const int16_t h = BTN_H(1);
+
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0)
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .font(Theme::font_medium)
+ .text( BTN_POS(1,1), w, h, GET_TEXT_F(MSG_SELECT_CHOCOLATE_TYPE));
+ #if ENABLED(COCOA_PRESS_EXTRA_HEATER)
+ if (has_extra_heater()) {
+ cmd.text( BTN_POS(2,1), w, h, GET_TEXT_F(MSG_EXTERNAL));
+ }
+ #endif
+ }
+
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.font(Theme::font_medium)
+ .colors(normal_btn)
+ .tag(2).button(BTN_POS(1,2), w, h, F("Dark Chocolate"))
+ .tag(3).button(BTN_POS(1,3), w, h, F("Milk Chocolate"))
+ .tag(4).button(BTN_POS(1,4), w, h, F("White Chocolate"));
+ #if ENABLED(COCOA_PRESS_EXTRA_HEATER)
+ if (has_extra_heater()) {
+ cmd.tag(5).button(BTN_POS(2,2), w, h, F("Dark Chocolate"))
+ .tag(6).button(BTN_POS(2,3), w, h, F("Milk Chocolate"))
+ .tag(7).button(BTN_POS(2,4), w, h, F("White Chocolate"));
+ }
+ #endif
+ cmd.colors(action_btn)
+ .tag(1) .button(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_BUTTON_DONE));
+ }
+}
+
+bool PreheatMenu::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); break;
+ case 2:
+ #ifdef COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_INT_SCRIPT
+ injectCommands(F(COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_INT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 3:
+ #ifdef COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_INT_SCRIPT
+ injectCommands(F(COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_INT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 4:
+ #ifdef COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_INT_SCRIPT
+ injectCommands(F(COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_INT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 5:
+ #ifdef COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_EXT_SCRIPT
+ injectCommands(F(COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_EXT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 6:
+ #ifdef COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_EXT_SCRIPT
+ injectCommands(F(COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_EXT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ case 7:
+ #ifdef COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_EXT_SCRIPT
+ injectCommands(F(COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_EXT_SCRIPT));
+ #endif
+ GOTO_SCREEN(PreheatTimerScreen);
+ break;
+ default: return false;
+ }
+ return true;
+}
+
+#endif // COCOA_PREHEAT_MENU
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_menu.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_menu.h
new file mode 100644
index 0000000..46bded7
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_menu.h
@@ -0,0 +1,31 @@
+/******************************
+ * cocoa_press/preheat_menu.h *
+ ******************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2020 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define COCOA_PREHEAT_MENU
+#define COCOA_PREHEAT_MENU_CLASS PreheatMenu
+
+class PreheatMenu : public BaseScreen, public CachedScreen {
+ public:
+ static void onRedraw(draw_mode_t);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_screen.cpp b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_screen.cpp
new file mode 100644
index 0000000..c4e9d97
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_screen.cpp
@@ -0,0 +1,161 @@
+/***************************************
+ * cocoapress/preheat_timer_screen.cpp *
+ ***************************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+#include "../screen_data.h"
+
+#ifdef COCOA_PREHEAT_SCREEN
+
+using namespace FTDI;
+using namespace ExtUI;
+using namespace Theme;
+
+constexpr static PreheatTimerScreenData &mydata = screen_data.PreheatTimerScreen;
+
+#define GRID_COLS 2
+#define GRID_ROWS 8
+
+#define HEADER_POS BTN_POS(2,1), BTN_SIZE(1,2)
+#define NOZZLE_ADJ_POS BTN_POS(2,3), BTN_SIZE(1,2)
+#define BODY_ADJ_POS BTN_POS(2,5), BTN_SIZE(1,2)
+#define CHAMBER_ADJ_POS BTN_POS(2,7), BTN_SIZE(1,2)
+#define PROGRESS_POS BTN_POS(1,1), BTN_SIZE(1,7)
+#define BACK_POS BTN_POS(1,8), BTN_SIZE(1,1)
+
+void PreheatTimerScreen::draw_message(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .cmd(COLOR_RGB(bg_text_enabled))
+ .tag(0);
+ draw_text_box(cmd, HEADER_POS, GET_TEXT_F(MSG_HEATING), OPT_CENTER, font_large);
+ }
+}
+
+uint16_t PreheatTimerScreen::secondsRemaining() {
+ const uint32_t elapsed_sec = (millis() - mydata.start_ms) / 1000;
+ return (COCOA_PRESS_PREHEAT_SECONDS > elapsed_sec) ? COCOA_PRESS_PREHEAT_SECONDS - elapsed_sec : 0;
+}
+
+void PreheatTimerScreen::draw_time_remaining(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ const uint16_t elapsed_sec = secondsRemaining();
+ const uint8_t min = elapsed_sec / 60,
+ sec = elapsed_sec % 60;
+
+ char str[10];
+ sprintf_P(str, PSTR("%02d:%02d"), min, sec);
+
+ CommandProcessor cmd;
+ cmd.font(font_xlarge);
+ draw_circular_progress(cmd, PROGRESS_POS, float(secondsRemaining()) * 100 / COCOA_PRESS_PREHEAT_SECONDS, str, theme_dark, theme_darkest);
+ }
+}
+
+void PreheatTimerScreen::draw_interaction_buttons(draw_mode_t what) {
+ if (what & FOREGROUND) {
+ CommandProcessor cmd;
+ cmd.colors(normal_btn)
+ .font(font_medium)
+ .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BUTTON_DONE));
+ }
+}
+
+void PreheatTimerScreen::draw_adjuster(draw_mode_t what, uint8_t tag, FSTR_P label, float value, int16_t x, int16_t y, int16_t w, int16_t h) {
+ #define SUB_COLS 9
+ #define SUB_ROWS 2
+
+ CommandProcessor cmd;
+ cmd.tag(0)
+ .font(font_small);
+ if (what & BACKGROUND) {
+ cmd.text( SUB_POS(1,1), SUB_SIZE(9,1), label)
+ .button(SUB_POS(1,2), SUB_SIZE(5,1), F(""), OPT_FLAT);
+ }
+
+ if (what & FOREGROUND) {
+ char str[32];
+ dtostrf(value, 5, 1, str);
+ strcat_P(str, PSTR(" "));
+ strcat_P(str, (const char*) GET_TEXT_F(MSG_UNITS_C));
+
+ cmd.text(SUB_POS(1,2), SUB_SIZE(5,1), str)
+ .font(font_medium)
+ .tag(tag ).button(SUB_POS(6,2), SUB_SIZE(2,1), F("-"))
+ .tag(tag+1).button(SUB_POS(8,2), SUB_SIZE(2,1), F("+"));
+ }
+}
+
+void PreheatTimerScreen::onEntry() {
+ mydata.start_ms = millis();
+}
+
+void PreheatTimerScreen::onRedraw(draw_mode_t what) {
+ draw_message(what);
+ draw_time_remaining(what);
+ draw_interaction_buttons(what);
+ draw_adjuster(what, 2, GET_TEXT_F(MSG_NOZZLE), getTargetTemp_celsius(E0), NOZZLE_ADJ_POS);
+ draw_adjuster(what, 4, GET_TEXT_F(MSG_BODY), getTargetTemp_celsius(E1), BODY_ADJ_POS);
+ draw_adjuster(what, 6, GET_TEXT_F(MSG_CHAMBER), getTargetTemp_celsius(CHAMBER), CHAMBER_ADJ_POS);
+}
+
+bool PreheatTimerScreen::onTouchHeld(uint8_t tag) {
+ const float increment = (tag == 6 || tag == 7) ? 1 : 0.1;
+ switch (tag) {
+ case 2: UI_DECREMENT(TargetTemp_celsius, E0); break;
+ case 3: UI_INCREMENT(TargetTemp_celsius, E0); break;
+ case 4: UI_DECREMENT(TargetTemp_celsius, E1); break;
+ case 5: UI_INCREMENT(TargetTemp_celsius, E1); break;
+ case 6: UI_DECREMENT(TargetTemp_celsius, CHAMBER); break;
+ case 7: UI_INCREMENT(TargetTemp_celsius, CHAMBER); break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool PreheatTimerScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: GOTO_PREVIOUS(); return true;
+ default: return current_screen.onTouchHeld(tag);
+ }
+ return false;
+}
+
+void PreheatTimerScreen::onIdle() {
+ if (secondsRemaining() == 0) {
+ AlertDialogBox::show(GET_TEXT_F(MSG_PREHEAT_FINISHED));
+ // Remove SaveSettingsDialogBox from the stack
+ // so the alert box doesn't return to me.
+ current_screen.forget();
+ }
+
+ reset_menu_timeout();
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ onRefresh();
+ refresh_timer.start();
+ }
+ BaseScreen::onIdle();
+}
+
+#endif // COCOA_PREHEAT_SCREEN
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_screen.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_screen.h
new file mode 100644
index 0000000..87628c4
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/preheat_screen.h
@@ -0,0 +1,46 @@
+/*********************************
+ * cocoapress/preheat_screen.cpp *
+ *********************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define COCOA_PREHEAT_SCREEN
+#define COCOA_PREHEAT_SCREEN_CLASS PreheatTimerScreen
+
+struct PreheatTimerScreenData {
+ uint32_t start_ms;
+};
+
+class PreheatTimerScreen : public BaseScreen, public CachedScreen {
+ private:
+ static uint16_t secondsRemaining();
+
+ static void draw_message(draw_mode_t);
+ static void draw_time_remaining(draw_mode_t);
+ static void draw_interaction_buttons(draw_mode_t);
+ static void draw_adjuster(draw_mode_t, uint8_t tag, FSTR_P label, float value, int16_t x, int16_t y, int16_t w, int16_t h);
+ public:
+ static void onRedraw(draw_mode_t);
+
+ static void onEntry();
+ static void onIdle();
+ static bool onTouchHeld(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/screens.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/screens.h
new file mode 100644
index 0000000..8481e44
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/screens.h
@@ -0,0 +1,134 @@
+/*************
+ * screens.h *
+ *************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+
+/********************************* DL CACHE SLOTS ******************************/
+
+// In order to reduce SPI traffic, we cache display lists (DL) in RAMG. This
+// is done using the CLCD::DLCache class, which takes a unique ID for each
+// cache location. These IDs are defined here:
+
+enum {
+ STATUS_SCREEN_CACHE,
+ MENU_SCREEN_CACHE,
+ TUNE_SCREEN_CACHE,
+ ALERT_BOX_CACHE,
+ SPINNER_CACHE,
+ ADVANCED_SETTINGS_SCREEN_CACHE,
+ MOVE_AXIS_SCREEN_CACHE,
+ TEMPERATURE_SCREEN_CACHE,
+ STEPS_SCREEN_CACHE,
+ MAX_FEEDRATE_SCREEN_CACHE,
+ MAX_VELOCITY_SCREEN_CACHE,
+ MAX_ACCELERATION_SCREEN_CACHE,
+ DEFAULT_ACCELERATION_SCREEN_CACHE,
+ FLOW_PERCENT_SCREEN_CACHE,
+ LEVELING_SCREEN_CACHE,
+ ZOFFSET_SCREEN_CACHE,
+ BED_MESH_VIEW_SCREEN_CACHE,
+ BED_MESH_EDIT_SCREEN_CACHE,
+ STEPPER_CURRENT_SCREEN_CACHE,
+ #if HAS_JUNCTION_DEVIATION
+ JUNC_DEV_SCREEN_CACHE,
+ #else
+ JERK_SCREEN_CACHE,
+ #endif
+ CASE_LIGHT_SCREEN_CACHE,
+ FILAMENT_MENU_CACHE,
+ LINEAR_ADVANCE_SCREEN_CACHE,
+ PREHEAT_MENU_CACHE,
+ PREHEAT_TIMER_SCREEN_CACHE,
+ LOAD_CHOCOLATE_SCREEN_CACHE,
+ MOVE_XYZ_SCREEN_CACHE,
+ MOVE_E_SCREEN_CACHE,
+ FILES_SCREEN_CACHE,
+ INTERFACE_SETTINGS_SCREEN_CACHE,
+ INTERFACE_SOUNDS_SCREEN_CACHE,
+ LOCK_SCREEN_CACHE,
+ DISPLAY_TIMINGS_SCREEN_CACHE
+};
+
+// To save MCU RAM, the status message is "baked" in to the status screen
+// cache, so we reserve a large chunk of memory for the DL cache
+
+#define STATUS_SCREEN_DL_SIZE 4096
+#define ALERT_BOX_DL_SIZE 3072
+#define SPINNER_DL_SIZE 3072
+#define FILE_SCREEN_DL_SIZE 4160
+#define PRINTING_SCREEN_DL_SIZE 2048
+
+/************************* MENU SCREEN DECLARATIONS *************************/
+
+#include "../generic/base_screen.h"
+#include "../generic/base_numeric_adjustment_screen.h"
+#include "../generic/dialog_box_base_class.h"
+#include "../generic/boot_screen.h"
+#include "../generic/about_screen.h"
+#include "../generic/kill_screen.h"
+#include "../generic/alert_dialog_box.h"
+#include "../generic/spinner_dialog_box.h"
+#include "../generic/restore_failsafe_dialog_box.h"
+#include "../generic/save_settings_dialog_box.h"
+#include "../generic/confirm_start_print_dialog_box.h"
+#include "../generic/confirm_abort_print_dialog_box.h"
+#include "../generic/confirm_user_request_alert_box.h"
+#include "../generic/touch_calibration_screen.h"
+#include "../generic/move_axis_screen.h"
+#include "../generic/steps_screen.h"
+#include "../generic/feedrate_percent_screen.h"
+#include "../generic/max_velocity_screen.h"
+#include "../generic/max_acceleration_screen.h"
+#include "../generic/default_acceleration_screen.h"
+#include "../generic/temperature_screen.h"
+#include "../generic/interface_sounds_screen.h"
+#include "../generic/interface_settings_screen.h"
+#include "../generic/lock_screen.h"
+#include "../generic/endstop_state_screen.h"
+#include "../generic/display_tuning_screen.h"
+#include "../generic/statistics_screen.h"
+#include "../generic/stepper_current_screen.h"
+#include "../generic/z_offset_screen.h"
+#include "../generic/bed_mesh_base.h"
+#include "../generic/bed_mesh_view_screen.h"
+#include "../generic/bed_mesh_edit_screen.h"
+#include "../generic/case_light_screen.h"
+#include "../generic/linear_advance_screen.h"
+#include "../generic/files_screen.h"
+#include "../generic/move_axis_screen.h"
+#include "../generic/flow_percent_screen.h"
+#if HAS_JUNCTION_DEVIATION
+ #include "../generic/junction_deviation_screen.h"
+#else
+ #include "../generic/jerk_screen.h"
+#endif
+
+#include "status_screen.h"
+#include "main_menu.h"
+#include "advanced_settings_menu.h"
+#include "preheat_menu.h"
+#include "preheat_screen.h"
+#include "load_chocolate.h"
+#include "leveling_menu.h"
+#include "move_xyz_screen.h"
+#include "move_e_screen.h"
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.cpp b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.cpp
new file mode 100644
index 0000000..00b2d6a
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.cpp
@@ -0,0 +1,307 @@
+/*********************************
+ * cocoa_press/status_screen.cpp *
+ *********************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../config.h"
+#include "../screens.h"
+
+#ifdef COCOA_STATUS_SCREEN
+
+#include "cocoa_press_ui.h"
+
+#define POLY(A) PolyUI::poly_reader_t(A, sizeof(A)/sizeof(A[0]))
+
+const uint8_t shadow_depth = 5;
+
+using namespace FTDI;
+using namespace Theme;
+using namespace ExtUI;
+
+float StatusScreen::increment;
+
+void StatusScreen::loadBitmaps() {
+ constexpr uint32_t base = ftdi_memory_map::RAM_G;
+
+ // Load fonts for internationalization
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_data(base + UTF8_FONT_OFFSET);
+ #endif
+}
+
+void StatusScreen::draw_progress(draw_mode_t what) {
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ int16_t x, y, h, v;
+
+ cmd.cmd(COLOR_RGB(accent_color_1));
+ cmd.font(font_medium);
+
+ if (what & BACKGROUND) {
+ ui.bounds(POLY(print_time_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_ELAPSED_PRINT));
+ }
+
+ if (what & FOREGROUND) {
+ const uint32_t elapsed = getProgress_seconds_elapsed();
+ const uint8_t hrs = elapsed/3600;
+ const uint8_t min = (elapsed/60)%60;
+
+ char str[10];
+ sprintf_P(str, PSTR(" %02d : %02d"), hrs, min);
+ ui.bounds(POLY(print_time_hms), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+
+ sprintf_P(str, PSTR("%-3d%%"), getProgress_percent() );
+ ui.bounds(POLY(print_time_percent), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ }
+}
+
+void StatusScreen::draw_temperature(draw_mode_t what) {
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ int16_t x, y, h, v;
+
+ if (what & BACKGROUND) {
+ cmd.cmd(COLOR_RGB(fluid_rgb));
+ cmd.font(font_medium).tag(10);
+
+ ui.bounds(POLY(chocolate_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_CHOCOLATE));
+
+ ui.bounds(POLY(h0_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_NOZZLE));
+
+ ui.bounds(POLY(h1_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_BODY));
+
+ #if ENABLED(COCOA_PRESS_EXTRA_HEATER)
+ if (has_extra_heater()) {
+ ui.bounds(POLY(h2_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_EXTERNAL));
+ }
+ #endif
+
+ ui.bounds(POLY(h3_label), x, y, h, v);
+ cmd.text(x, y, h, v, GET_TEXT_F(MSG_CHAMBER));
+
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd); // Restore font bitmap handles
+ #endif
+ }
+
+ if (what & FOREGROUND) {
+ char str[15];
+ cmd.cmd(COLOR_RGB(fluid_rgb));
+
+ cmd.font(font_large).tag(10);
+
+ format_temp(str, getActualTemp_celsius(E0));
+ ui.bounds(POLY(h0_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+
+ format_temp(str, getActualTemp_celsius(E1));
+ ui.bounds(POLY(h1_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+
+ #if ENABLED(COCOA_PRESS_EXTRA_HEATER)
+ if (has_extra_heater()) {
+ format_temp(str, getActualTemp_celsius(E2));
+ ui.bounds(POLY(h2_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ }
+ #endif
+
+ format_temp(str, getActualTemp_celsius(CHAMBER));
+ ui.bounds(POLY(h3_temp), x, y, h, v);
+ cmd.text(x, y, h, v, str);
+ }
+}
+
+void StatusScreen::draw_syringe(draw_mode_t what) {
+ #if ENABLED(COCOA_PRESS_CHOCOLATE_LEVEL_SENSOR)
+ const float fill_level = get_chocolate_fill_level();
+ #else
+ constexpr float fill_level = 1.0f;
+ #endif
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ if (what & BACKGROUND) {
+ // Paint the shadow for the syringe
+ ui.color(shadow_rgb);
+ ui.shadow(POLY(syringe_outline), shadow_depth);
+ }
+
+ if (what & FOREGROUND) {
+ int16_t x, y, h, v;
+
+ // Paint the syringe icon
+ ui.color(syringe_rgb);
+ ui.fill(POLY(syringe_outline));
+
+ ui.color(fluid_rgb);
+ ui.bounds(POLY(syringe_fluid), x, y, h, v);
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(SCISSOR_XY(x,y + v * (1.0 - fill_level)));
+ cmd.cmd(SCISSOR_SIZE(h, v * fill_level));
+ ui.fill(POLY(syringe_fluid), false);
+ cmd.cmd(RESTORE_CONTEXT());
+
+ ui.color(stroke_rgb);
+ ui.fill(POLY(syringe));
+ }
+}
+
+void StatusScreen::draw_buttons(draw_mode_t what) {
+ int16_t x, y, h, v;
+
+ const bool can_print = isMediaInserted() && !isPrintingFromMedia();
+ const bool sdOrHostPrinting = ExtUI::isPrinting();
+ const bool sdOrHostPaused = ExtUI::isPrintingPaused();
+
+ CommandProcessor cmd;
+ PolyUI ui(cmd, what);
+
+ cmd.font(font_medium).colors(normal_btn);
+
+ ui.bounds(POLY(park_btn), x, y, h, v);
+ cmd.tag(1).button(x, y, h, v, GET_TEXT_F(MSG_FILAMENT_PARK_ENABLED));
+
+ ui.bounds(POLY(load_chocolate_btn), x, y, h, v);
+ cmd.tag(2).button(x, y, h, v, GET_TEXT_F(MSG_LOAD_UNLOAD));
+
+ ui.bounds(POLY(preheat_chocolate_btn), x, y, h, v);
+ cmd.tag(3).button(x, y, h, v, GET_TEXT_F(MSG_PREHEAT_CHOCOLATE));
+
+ ui.bounds(POLY(menu_btn), x, y, h, v);
+ cmd.tag(4).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_MENU));
+
+ ui.bounds(POLY(pause_btn), x, y, h, v);
+ cmd.tag(sdOrHostPaused ? 6 : 5).enabled(sdOrHostPrinting).button(x, y, h, v, sdOrHostPaused ? GET_TEXT_F(MSG_BUTTON_RESUME) : GET_TEXT_F(MSG_BUTTON_PAUSE));
+
+ ui.bounds(POLY(stop_btn), x, y, h, v);
+ cmd.tag(7).enabled(sdOrHostPrinting).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_STOP));
+
+ ui.bounds(POLY(extrude_btn), x, y, h, v);
+ cmd.tag(8).button(x, y, h, v, GET_TEXT_F(MSG_EXTRUDE));
+
+ ui.bounds(POLY(print_btn), x, y, h, v);
+ cmd.tag(9).colors(action_btn).enabled(can_print).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_PRINT));
+}
+
+void StatusScreen::onRedraw(draw_mode_t what) {
+ if (what & BACKGROUND) {
+ CommandProcessor cmd;
+ cmd.cmd(CLEAR_COLOR_RGB(bg_color))
+ .cmd(CLEAR(true,true,true))
+ .tag(0);
+ }
+
+ draw_progress(what);
+ draw_syringe(what);
+ draw_temperature(what);
+ draw_buttons(what);
+}
+
+bool StatusScreen::onTouchStart(uint8_t) {
+ increment = 0;
+ return true;
+}
+
+bool StatusScreen::onTouchEnd(uint8_t tag) {
+ switch (tag) {
+ case 1: SpinnerDialogBox::enqueueAndWait(F("G28 O\nG27")); break;
+ case 2: GOTO_SCREEN(LoadChocolateScreen); break;
+ case 3: GOTO_SCREEN(PreheatMenu); break;
+ case 4: GOTO_SCREEN(MainMenu); break;
+ case 5:
+ sound.play(twinkle, PLAY_ASYNCHRONOUS);
+ if (ExtUI::isPrintingFromMedia())
+ ExtUI::pausePrint();
+ #ifdef ACTION_ON_PAUSE
+ else hostui.pause();
+ #endif
+ GOTO_SCREEN(StatusScreen);
+ break;
+ case 6:
+ sound.play(twinkle, PLAY_ASYNCHRONOUS);
+ if (ExtUI::isPrintingFromMedia())
+ ExtUI::resumePrint();
+ #ifdef ACTION_ON_RESUME
+ else hostui.resume();
+ #endif
+ GOTO_SCREEN(StatusScreen);
+ break;
+ case 7:
+ GOTO_SCREEN(ConfirmAbortPrintDialogBox);
+ current_screen.forget();
+ PUSH_SCREEN(StatusScreen);
+ break;
+ case 9: GOTO_SCREEN(FilesScreen); break;
+ case 10: GOTO_SCREEN(TemperatureScreen); break;
+ default: return false;
+ }
+ // If a passcode is enabled, the LockScreen will prevent the
+ // user from proceeding.
+ LockScreen::check_passcode();
+ return true;
+}
+
+bool StatusScreen::onTouchHeld(uint8_t tag) {
+ if (tag == 8 && !ExtUI::isMoving()) {
+ LoadChocolateScreen::setManualFeedrateAndIncrement(1, increment);
+ UI_INCREMENT(AxisPosition_mm, E0);
+ current_screen.onRefresh();
+ }
+ return false;
+}
+
+void StatusScreen::setStatusMessage(FSTR_P) {
+}
+
+void StatusScreen::setStatusMessage(const char * const) {
+}
+
+void StatusScreen::onIdle() {
+ reset_menu_timeout();
+ if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
+ if (!EventLoop::is_touch_held())
+ onRefresh();
+ refresh_timer.start();
+ }
+}
+
+void StatusScreen::onMediaInserted() {
+ if (AT_SCREEN(StatusScreen))
+ setStatusMessage(GET_TEXT_F(MSG_MEDIA_INSERTED));
+}
+
+void StatusScreen::onMediaRemoved() {
+ if (AT_SCREEN(StatusScreen) || ExtUI::isPrintingFromMedia())
+ setStatusMessage(GET_TEXT_F(MSG_MEDIA_REMOVED));
+}
+
+#endif // COCOA_STATUS_SCREEN
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.h b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.h
new file mode 100644
index 0000000..08fb6f2
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/cocoa_press/status_screen.h
@@ -0,0 +1,57 @@
+/*******************************
+ * cocoa_press/status_screen.h *
+ *******************************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define COCOA_STATUS_SCREEN
+#define COCOA_STATUS_SCREEN_CLASS StatusScreen
+
+class StatusScreen : public BaseScreen, public CachedScreen {
+ private:
+ static float increment;
+ static bool jog_xy;
+ static bool fine_motion;
+
+ static void draw_progress(draw_mode_t what);
+ static void draw_temperature(draw_mode_t what);
+ static void draw_syringe(draw_mode_t what);
+ static void draw_arrows(draw_mode_t what);
+ static void draw_overlay_icons(draw_mode_t what);
+ static void draw_fine_motion(draw_mode_t what);
+ static void draw_buttons(draw_mode_t what);
+ public:
+ static void loadBitmaps();
+ static void unlockMotors();
+
+ static void setStatusMessage(const char *);
+ static void setStatusMessage(FSTR_P);
+
+ static void onRedraw(draw_mode_t);
+
+ static bool onTouchStart(uint8_t tag);
+ static bool onTouchHeld(uint8_t tag);
+ static bool onTouchEnd(uint8_t tag);
+ static void onIdle();
+ static void onMediaInserted();
+ static void onMediaRemoved();
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/compat.h b/src/lcd/extui/ftdi_eve_touch_ui/compat.h
new file mode 100644
index 0000000..afb380a
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/compat.h
@@ -0,0 +1,53 @@
+/************
+ * compat.h *
+ ************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * This following provides compatibility whether compiling
+ * as a part of Marlin or outside it
+ */
+
+#ifdef __has_include
+ #if __has_include("../ui_api.h")
+ #include "../ui_api.h"
+ #endif
+#else
+ #include "../ui_api.h"
+#endif
+
+#ifdef __MARLIN_FIRMWARE__
+ // __MARLIN_FIRMWARE__ exists when compiled within Marlin.
+ #include "pin_mappings.h"
+ #undef max
+ #define max(a,b) ((a)>(b)?(a):(b))
+ #undef min
+ #define min(a,b) ((a)<(b)?(a):(b))
+#else
+ namespace UI {
+ static uint32_t safe_millis() { return millis(); }
+ static void yield() {}
+ };
+#endif
+
+class __FlashStringHelper;
+typedef const __FlashStringHelper *FSTR_P;
+extern const char G28_STR[];
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/config.h b/src/lcd/extui/ftdi_eve_touch_ui/config.h
new file mode 100644
index 0000000..05e19b2
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/config.h
@@ -0,0 +1,30 @@
+/************
+ * config.h *
+ ************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+// Configure this display with options in Configuration_adv.h
+#include "../../../inc/MarlinConfigPre.h"
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "compat.h"
+
+#endif
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp
new file mode 100644
index 0000000..2ce9ed0
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp
@@ -0,0 +1,160 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 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 .
+ *
+ */
+
+/**
+ * lcd/extui/ftdi_eve_touch_ui/ftdi_eve_extui.cpp
+ */
+
+#include "../../../inc/MarlinConfigPre.h"
+
+#if ENABLED(TOUCH_UI_FTDI_EVE)
+
+#include "screens.h"
+
+namespace ExtUI {
+ using namespace Theme;
+ using namespace FTDI;
+
+ void onStartup() { EventLoop::setup(); }
+
+ void onIdle() { EventLoop::loop(); }
+
+ void onPrinterKilled(FSTR_P const error, FSTR_P const component) {
+ char str[strlen_P(FTOP(error)) + strlen_P(FTOP(component)) + 3];
+ sprintf_P(str, PSTR(S_FMT ": " S_FMT), FTOP(error), FTOP(component));
+ KillScreen::show(str);
+ }
+
+ void onMediaInserted() {
+ #if ENABLED(SDSUPPORT)
+ sound.play(media_inserted, PLAY_ASYNCHRONOUS);
+ StatusScreen::onMediaInserted();
+ #endif
+ }
+
+ void onMediaRemoved() {
+ #if ENABLED(SDSUPPORT)
+ if (isPrintingFromMedia()) {
+ stopPrint();
+ InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FAILED);
+ }
+ else
+ sound.play(media_removed, PLAY_ASYNCHRONOUS);
+
+ StatusScreen::onMediaRemoved();
+ FilesScreen::onMediaRemoved();
+ #endif
+ }
+
+ void onMediaError() {
+ sound.play(sad_trombone, PLAY_ASYNCHRONOUS);
+ AlertDialogBox::showError(F("Unable to read media."));
+ }
+
+ void onStatusChanged(const char *lcd_msg) { StatusScreen::setStatusMessage(lcd_msg); }
+
+ void onPrintTimerStarted() {
+ InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_STARTED);
+ }
+ void onPrintTimerStopped() {
+ InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FINISHED);
+ }
+
+ void onPrintTimerPaused() {}
+ void onPrintDone() {}
+
+ void onFilamentRunout(const extruder_t extruder) {
+ char lcd_msg[30];
+ sprintf_P(lcd_msg, PSTR("Extruder %d Filament Error"), extruder + 1);
+ StatusScreen::setStatusMessage(lcd_msg);
+ InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FAILED, FTDI::PLAY_SYNCHRONOUS);
+ }
+
+ void onHomingStart() {}
+ void onHomingDone() {}
+
+ void onFactoryReset() { InterfaceSettingsScreen::defaultSettings(); }
+ void onStoreSettings(char *buff) { InterfaceSettingsScreen::saveSettings(buff); }
+ void onLoadSettings(const char *buff) { InterfaceSettingsScreen::loadSettings(buff); }
+ void onPostprocessSettings() {} // Called after loading or resetting stored settings
+
+ void onSettingsStored(bool success) {
+ #ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE
+ if (success && InterfaceSettingsScreen::backupEEPROM()) {
+ SERIAL_ECHOLNPGM("EEPROM backed up to SPI Flash");
+ }
+ #else
+ UNUSED(success);
+ #endif
+ }
+ void onSettingsLoaded(bool) {}
+
+ void onPlayTone(const uint16_t frequency, const uint16_t duration) { sound.play_tone(frequency, duration); }
+
+ void onUserConfirmRequired(const char * const msg) {
+ if (msg)
+ ConfirmUserRequestAlertBox::show(msg);
+ else
+ ConfirmUserRequestAlertBox::hide();
+ }
+
+ #if HAS_LEVELING && HAS_MESH
+ void onLevelingStart() {}
+ void onLevelingDone() {}
+ void onMeshUpdate(const int8_t x, const int8_t y, const_float_t val) { BedMeshViewScreen::onMeshUpdate(x, y, val); }
+ void onMeshUpdate(const int8_t x, const int8_t y, const ExtUI::probe_state_t state) { BedMeshViewScreen::onMeshUpdate(x, y, state); }
+ #endif
+
+ #if ENABLED(POWER_LOSS_RECOVERY)
+ void onPowerLossResume() {} // Called on resume from power-loss
+ #endif
+
+ #if HAS_PID_HEATING
+ void onPidTuning(const result_t rst) {
+ // Called for temperature PID tuning result
+ //SERIAL_ECHOLNPGM("OnPidTuning:", rst);
+ switch (rst) {
+ case PID_STARTED:
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_AUTOTUNE));
+ break;
+ case PID_BAD_EXTRUDER_NUM:
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_BAD_EXTRUDER_NUM));
+ break;
+ case PID_TEMP_TOO_HIGH:
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_TEMP_TOO_HIGH));
+ break;
+ case PID_TUNING_TIMEOUT:
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_TIMEOUT));
+ break;
+ case PID_DONE:
+ StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PID_AUTOTUNE_DONE));
+ break;
+ }
+ GOTO_SCREEN(StatusScreen);
+ }
+ #endif // HAS_PID_HEATING
+
+ void onSteppersDisabled() {}
+ void onSteppersEnabled() {}
+}
+
+#endif // TOUCH_UI_FTDI_EVE
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt
new file mode 100644
index 0000000..8859f3d
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ 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 .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/README.md b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/README.md
new file mode 100644
index 0000000..9bdf784
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/README.md
@@ -0,0 +1,28 @@
+FTDI EVE Library
+----------------
+
+The FTDI EVE Library is a fully open-source library and UI framework for the FTDI
+FT800 and FT810 graphics processor.
+
+Although the library has been developed within Lulzbot for providing a user interface
+for Marlin, the library has been written so that it can be used in any Arduino sketch.
+
+The library is split into two parts. The "basic" API provides a shallow interface to
+the underlying FTDI hardware and command FIFO and provides low-level access to the
+hardware as closely as possible to the API described in the FTDI Programmer's Guide.
+
+The "extended" API builds on top of the "basic" API to provide a GUI framework for
+handling common challenges in building a usable GUI. The GUI framework provides the
+following features:
+
+- Macros for a resolution-independent placement of widgets based on a grid.
+- Class-based UI screens, with press and unpress touch events, as well as touch repeat.
+- Event loop with button debouncing and button push visual and auditory feedback.
+- Easy screen-to-screen navigation including a navigation stack for going backwards.
+- Visual feedback for disabled vs enabled buttons, and custom button styles.
+- A sound player class for playing individual notes or complete sound sequences.
+- Display list caching, for storing static background elements of a screen in RAM_G.
+
+See the "examples" folder for Arduino sketches. Modify the "src/config.h" file in
+each to suit your particular setup. The "sample_configs" contain sample configuration
+files for running the sketches on our 3D printer boards.
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h
new file mode 100644
index 0000000..5168ef7
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h
@@ -0,0 +1,281 @@
+/************
+ * boards.h *
+ ************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define HAS_RESOLUTION (defined(TOUCH_UI_320x240) || defined(TOUCH_UI_480x272) || defined(TOUCH_UI_800x480))
+
+#define IS_FT800 \
+ constexpr uint16_t ftdi_chip = 800; \
+ using namespace FTDI_FT800; \
+ namespace DL { \
+ using namespace FTDI_FT800_DL; \
+ } \
+ typedef ft800_memory_map ftdi_memory_map; \
+ typedef ft800_registers ftdi_registers;
+
+#define IS_FT810 \
+ constexpr uint16_t ftdi_chip = 810; \
+ using namespace FTDI_FT810; \
+ namespace DL { \
+ using namespace FTDI_FT800_DL; \
+ using namespace FTDI_FT810_DL; \
+ } \
+ typedef ft810_memory_map ftdi_memory_map; \
+ typedef ft810_registers ftdi_registers;
+
+#ifdef LCD_FTDI_VM800B35A
+ #if !HAS_RESOLUTION
+ #define TOUCH_UI_320x240
+ #endif
+ #ifndef FTDI_API_LEVEL
+ #define FTDI_API_LEVEL 800
+ #endif
+ namespace FTDI {
+ IS_FT800
+ constexpr bool Use_Crystal = true; // 0 = use internal oscillator, 1 = module has a crystal populated
+ constexpr bool GPIO_0_Audio_Enable = false; /* 1 = does use GPIO00 for amplifier control, 0 = not in use for Audio */
+ constexpr bool GPIO_1_Audio_Shutdown = true; /* 1 = does use GPIO01 for amplifier control, 0 = not in use for Audio */
+ constexpr uint8_t Swizzle = 2;
+ constexpr uint8_t CSpread = 1;
+
+ constexpr uint16_t touch_threshold = 1200; /* touch-sensitivity */
+ }
+
+/**
+ * Settings for the Haoyu Electronics, 4.3" Graphical LCD Touchscreen, 480x272, SPI, FT800 (FT800CB-HY43B)
+ * and 5" Graphical LCD Touchscreen, 480x272, SPI, FT800 (FT800CB-HY50B)
+ * http://www.hotmcu.com/43-graphical-lcd-touchscreen-480x272-spi-ft800-p-111.html?cPath=6_16
+ * http://www.hotmcu.com/5-graphical-lcd-touchscreen-480x272-spi-ft800-p-124.html?cPath=6_16
+ * Datasheet:
+ * https://www.hantronix.com/files/data/1278363262430-3.pdf
+ * https://www.haoyuelectronics.com/Attachment/HY43-LCD/LCD%20DataSheet.pdf
+ * https://www.haoyuelectronics.com/Attachment/HY5-LCD-HD/KD50G21-40NT-A1.pdf
+ */
+#elif defined(LCD_HAOYU_FT800CB)
+ #if !HAS_RESOLUTION
+ #define TOUCH_UI_480x272
+ #endif
+ #ifndef FTDI_API_LEVEL
+ #define FTDI_API_LEVEL 800
+ #endif
+ namespace FTDI {
+ IS_FT800
+ constexpr bool Use_Crystal = true; // 0 = use internal oscillator, 1 = module has a crystal populated
+ constexpr bool GPIO_0_Audio_Enable = false;
+ constexpr bool GPIO_1_Audio_Shutdown = false;
+ constexpr uint8_t Swizzle = 0;
+ constexpr uint8_t CSpread = 1;
+ constexpr uint16_t touch_threshold = 2000; /* touch-sensitivity */
+ }
+
+/**
+ * Settings for the Haoyu Electronics, 5" Graphical LCD Touchscreen, 800x480, SPI, FT810
+ * http://www.hotmcu.com/5-graphical-lcd-touchscreen-800x480-spi-ft810-p-286.html
+ * Datasheet:
+ * https://www.haoyuelectronics.com/Attachment/HY5-LCD-HD/KD50G21-40NT-A1.pdf
+ */
+#elif defined(LCD_HAOYU_FT810CB)
+ #if !HAS_RESOLUTION
+ #define TOUCH_UI_800x480
+ #endif
+ #ifndef FTDI_API_LEVEL
+ #define FTDI_API_LEVEL 810
+ #endif
+ namespace FTDI {
+ IS_FT810
+ constexpr bool Use_Crystal = true; // 0 = use internal oscillator, 1 = module has a crystal populated
+ constexpr bool GPIO_0_Audio_Enable = false;
+ constexpr bool GPIO_1_Audio_Shutdown = false;
+ constexpr uint8_t Swizzle = 0;
+ constexpr uint8_t CSpread = 1;
+ constexpr uint16_t touch_threshold = 2000; /* touch-sensitivity */
+ }
+
+/**
+ * Settings for the 4D Systems, 4.3" Embedded SPI Display 480x272, SPI, FT800 (4DLCD-FT843)
+ * https://4dsystems.com.au/4dlcd-ft843
+ * Datasheet:
+ * https://4dsystems.com.au/mwdownloads/download/link/id/52/
+ */
+#elif defined(LCD_4DSYSTEMS_4DLCD_FT843)
+ #if !HAS_RESOLUTION
+ #define TOUCH_UI_480x272
+ #endif
+ #ifndef FTDI_API_LEVEL
+ #define FTDI_API_LEVEL 800
+ #endif
+ namespace FTDI {
+ IS_FT800
+ constexpr bool Use_Crystal = true; // 0 = use internal oscillator, 1 = module has a crystal populated
+ constexpr bool GPIO_0_Audio_Enable = false;
+ constexpr bool GPIO_1_Audio_Shutdown = true;
+ constexpr uint8_t Swizzle = 0;
+ constexpr uint8_t CSpread = 1;
+ constexpr uint16_t touch_threshold = 1200; /* touch-sensitivity */
+ }
+
+/**
+ * Settings for the Aleph Objects Color LCD User Interface
+ * Datasheet https://www.hantronix.com/files/data/s1501799605s500-gh7.pdf
+ */
+#elif defined(LCD_LULZBOT_CLCD_UI)
+ #if !HAS_RESOLUTION
+ #define TOUCH_UI_800x480
+ #endif
+ #ifndef FTDI_API_LEVEL
+ #define FTDI_API_LEVEL 810
+ #endif
+ namespace FTDI {
+ IS_FT810
+ constexpr bool Use_Crystal = false; // 0 = use internal oscillator, 1 = module has a crystal populated
+ constexpr bool GPIO_0_Audio_Enable = true; // The AO CLCD uses GPIO0 to enable audio
+ constexpr bool GPIO_1_Audio_Shutdown = false;
+ constexpr uint8_t Swizzle = 0;
+ constexpr uint8_t CSpread = 0;
+ constexpr uint16_t touch_threshold = 2000; /* touch-sensitivity */
+ }
+
+/**
+ * FYSETC Color LCD
+ * https://www.aliexpress.com/item/4000627651757.html
+ * Product information:
+ * https://github.com/FYSETC/TFT81050
+ */
+#elif defined(LCD_FYSETC_TFT81050)
+ #if !HAS_RESOLUTION
+ #define TOUCH_UI_800x480
+ #endif
+ #ifndef FTDI_API_LEVEL
+ #define FTDI_API_LEVEL 810
+ #endif
+ namespace FTDI {
+ IS_FT810
+ constexpr bool Use_Crystal = false; // 0 = use internal oscillator, 1 = module has a crystal populated
+ constexpr bool GPIO_0_Audio_Enable = true; // The AO CLCD uses GPIO0 to enable audio
+ constexpr bool GPIO_1_Audio_Shutdown = false;
+ constexpr uint8_t Swizzle = 0;
+ constexpr uint8_t CSpread = 0;
+ constexpr uint16_t touch_threshold = 2000; /* touch-sensitivity */
+ }
+
+/**
+ * Settings for EVE3-50G - Matrix Orbital 5.0" 800x480, BT815
+ * https://www.matrixorbital.com/ftdi-eve/eve-bt815-bt816/eve3-50g
+ * use for example with: https://github.com/RudolphRiedel/EVE_display-adapter
+ */
+#elif defined(LCD_EVE3_50G)
+ #if !HAS_RESOLUTION
+ #define TOUCH_UI_800x480
+ #define TOUCH_UI_800x480_GENERIC // use more common timing parameters as the original set
+ #endif
+ #ifndef FTDI_API_LEVEL
+ #define FTDI_API_LEVEL 810
+ #endif
+ namespace FTDI {
+ IS_FT810
+ constexpr bool Use_Crystal = true; // 0 = use internal oscillator, 1 = module has a crystal populated
+ constexpr bool GPIO_0_Audio_Enable = false;
+ constexpr bool GPIO_1_Audio_Shutdown = false;
+ #define USE_GT911 // this display uses an alternative touch-controller and we need to tell the init function to switch
+ constexpr uint8_t Swizzle = 0;
+ constexpr uint8_t CSpread = 1;
+ constexpr uint8_t Pclkpol = 1;
+ constexpr uint16_t touch_threshold = 1200; /* touch-sensitivity */
+
+ constexpr uint32_t default_transform_a = 0x000109E4;
+ constexpr uint32_t default_transform_b = 0x000007A6;
+ constexpr uint32_t default_transform_c = 0xFFEC1EBA;
+ constexpr uint32_t default_transform_d = 0x0000072C;
+ constexpr uint32_t default_transform_e = 0x0001096A;
+ constexpr uint32_t default_transform_f = 0xFFF469CF;
+ }
+
+/**
+ * Settings for EVE2-50G - Matrix Orbital 5.0" 800x480, FT813
+ * https://www.matrixorbital.com/ftdi-eve/eve-bt815-bt816/eve3-50g
+ * use for example with: https://github.com/RudolphRiedel/EVE_display-adapter
+ */
+#elif defined(LCD_EVE2_50G)
+ #if !HAS_RESOLUTION
+ #define TOUCH_UI_800x480
+ #define TOUCH_UI_800x480_GENERIC // use more common timing parameters as the original set
+ #endif
+ #ifndef FTDI_API_LEVEL
+ #define FTDI_API_LEVEL 810
+ #endif
+ namespace FTDI {
+ IS_FT810
+ constexpr bool Use_Crystal = false; // 0 = use internal oscillator, 1 = module has a crystal populated
+ constexpr bool GPIO_0_Audio_Enable = false;
+ constexpr bool GPIO_1_Audio_Shutdown = false;
+ #define PATCH_GT911 // this display uses an alternative touch-controller and we need to tell the init function to patch the FT813 for it
+ constexpr uint8_t Pclkpol = 1;
+ constexpr uint8_t Swizzle = 0;
+ constexpr uint8_t CSpread = 1;
+ constexpr uint16_t touch_threshold = 1200; /* touch-sensitivity */
+
+ constexpr uint32_t default_transform_a = 0x000109E4;
+ constexpr uint32_t default_transform_b = 0x000007A6;
+ constexpr uint32_t default_transform_c = 0xFFEC1EBA;
+ constexpr uint32_t default_transform_d = 0x0000072C;
+ constexpr uint32_t default_transform_e = 0x0001096A;
+ constexpr uint32_t default_transform_f = 0xFFF469CF;
+ }
+
+#else
+
+ #error "Unknown or no TOUCH_UI_FTDI_EVE board specified. To add a new board, modify this file."
+
+#endif
+
+
+/* this data is used to patch FT813 displays that use a GT911 as a touch-controller */
+#ifdef PATCH_GT911
+ constexpr PROGMEM unsigned char GT911_data[] = {
+ 26,255,255,255,32,32,48,0,4,0,0,0,2,0,0,0,
+ 34,255,255,255,0,176,48,0,120,218,237,84,221,111,84,69,20,63,51,179,93,160,148,101,111,76,5,44,141,123,111,161,11,219,154,16,9,16,17,229,156,75,26,11,13,21,227,3,16,252,184,179,
+ 45,219,143,45,41,125,144,72,67,100,150,71,189,113,18,36,17,165,100,165,198,16,32,17,149,196,240,128,161,16,164,38,54,240,0,209,72,130,15,38,125,48,66,82,30,76,19,31,172,103,46,
+ 139,24,255,4,227,157,204,156,51,115,102,206,231,239,220,5,170,94,129,137,75,194,216,98,94,103,117,115,121,76,131,177,125,89,125,82,123,60,243,58,142,242,204,185,243,188,118,156,
+ 227,155,203,238,238,195,251,205,229,71,92,28,169,190,184,84,143,113,137,53,244,103,181,237,87,253,113,137,233,48,12,198,165,181,104,139,25,84,253,155,114,74,191,0,54,138,163,
+ 12,62,131,207,129,23,217,34,91,31,128,65,246,163,175,213,8,147,213,107,35,203,94,108,3,111,40,171,83,24,15,165,177,222,116,97,23,188,140,206,150,42,102,181,87,78,86,182,170,134,
+ 215,241,121,26,243,252,2,76,115,217,139,222,206,173,136,132,81,61,35,185,39,113,23,46,199,76,178,54,151,183,224,0,40,189,28,149,182,58,131,79,152,30,76,34,98,234,162,216,133,141,
+ 102,39,170,40,192,101,53,201,146,191,37,77,44,177,209,74,211,5,206,187,5,6,216,47,53,96,123,22,50,103,251,192,84,17,74,227,185,56,106,51,91,161,96,182,163,48,171,141,139,65,152,
+ 66,66,11,102,43,158,75,36,80,147,184,147,139,112,17,235,216,103,111,239,245,92,10,175,194,40,44,58,125,5,59,112,50,103,245,4,78,192,5,156,194,51,60,191,134,75,110,173,237,46,192,
+ 121,156,192,115,184,218,120,67,63,115,46,11,102,10,97,232,50,235,114,182,148,118,178,41,188,12,135,77,202,124,12,96,238,35,161,234,189,129,23,249,212,139,230,25,53,48,205,52,93,
+ 163,117,53,154,170,81,85,163,178,70,69,66,167,241,14,46,241,1,226,136,152,179,197,59,184,148,254,49,132,48,15,176,137,192,76,131,196,105,104,162,86,81,160,165,255,26,173,162,137,
+ 86,145,210,183,192,55,175,194,211,60,91,120,230,184,174,27,41,131,155,40,224,29,87,179,232,16,55,55,7,165,147,81,23,165,49,101,54,224,75,180,81,108,18,29,226,69,225,110,175,224,
+ 42,212,25,47,130,193,110,234,192,215,252,56,74,162,24,46,251,174,54,106,68,245,14,9,155,160,22,120,207,104,240,29,90,178,140,28,24,220,47,166,112,61,251,208,192,111,56,239,238,
+ 93,255,251,62,99,32,193,75,61,190,235,123,229,110,218,194,85,79,225,59,98,20,238,227,235,220,11,221,149,25,180,116,194,159,111,96,192,24,213,59,139,179,156,215,69,230,19,24,35,
+ 135,117,206,171,206,162,67,129,234,61,235,11,104,103,84,64,223,167,254,40,163,101,92,84,43,150,46,249,219,205,7,116,11,91,104,61,57,75,223,8,48,25,28,119,252,222,113,49,86,249,
+ 74,180,211,156,181,61,215,168,157,7,251,199,150,242,250,91,58,132,94,121,7,53,151,139,98,6,165,153,69,214,32,110,211,100,101,31,89,45,81,98,23,205,205,197,209,109,186,198,35,
+ 141,191,249,25,60,132,223,153,251,98,20,239,146,139,20,217,250,41,250,137,58,177,90,57,79,51,108,233,20,253,194,187,49,222,205,114,141,96,48,175,219,107,54,111,138,22,154,103,
+ 108,79,58,252,179,178,79,164,195,2,153,36,39,170,199,201,167,197,85,106,8,59,177,81,46,56,2,230,75,114,17,55,112,188,65,208,137,77,114,10,115,55,58,208,197,173,122,87,6,140,
+ 110,42,208,124,163,70,108,241,104,18,245,98,214,187,134,53,42,221,22,182,133,211,116,148,177,194,209,192,85,90,199,58,55,203,2,229,19,137,187,161,228,154,112,203,145,125,244,
+ 188,220,118,228,41,201,181,41,195,144,215,183,51,80,250,21,217,16,217,200,235,109,227,188,122,218,142,60,170,224,112,240,184,130,229,224,113,5,223,148,163,80,165,183,130,187,
+ 132,116,64,238,161,85,220,115,139,205,98,227,244,29,102,125,7,37,243,123,223,11,26,92,63,243,116,61,191,138,123,244,160,84,186,74,31,5,174,247,119,135,199,248,253,135,242,97,
+ 102,145,190,144,14,85,238,221,231,193,158,48,205,25,120,248,15,220,29,158,9,70,185,30,103,229,33,254,23,237,160,172,62,193,90,222,224,232,14,200,56,90,104,142,227,120,110,6,
+ 21,211,203,65,150,99,151,220,247,87,164,50,159,49,239,234,58,142,0,109,108,123,18,79,227,36,100,248,222,205,96,127,120,26,171,228,69,63,36,17,252,200,17,116,242,187,227,88,143,
+ 247,2,75,191,6,130,59,188,11,55,240,31,243,122,152,226,183,207,154,73,188,39,219,43,105,222,87,41,143,141,140,175,73,112,184,252,61,184,16,90,250,35,168,82,119,176,57,116,94,
+ 200,150,22,190,179,44,104,12,235,84,149,102,252,89,154,193,99,228,106,242,125,248,64,194,255,223,127,242,83,11,255,2,70,214,226,128,0,0
+ };
+#endif // PATCH_GT911
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp
new file mode 100644
index 0000000..662753a
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp
@@ -0,0 +1,1218 @@
+/****************
+ * commands.cpp *
+ ****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_basic.h"
+
+#ifdef FTDI_BASIC
+
+#define MULTIPLE_OF_4(val) ((((val)+3)>>2)<<2)
+
+using namespace FTDI;
+using namespace FTDI::SPI;
+
+void CLCD::enable() {
+ mem_write_8(REG::PCLK, Pclk);
+}
+
+void CLCD::disable() {
+ mem_write_8(REG::PCLK, 0x00);
+}
+
+void CLCD::set_brightness(uint8_t brightness) {
+ mem_write_8(REG::PWM_DUTY, min(128,brightness));
+}
+
+uint8_t CLCD::get_brightness() {
+ return mem_read_8(REG::PWM_DUTY);
+}
+
+void CLCD::turn_on_backlight() {
+ mem_write_8(REG::PWM_DUTY, 128);
+}
+
+void CLCD::FontMetrics::load(const uint8_t font) {
+ static_assert(sizeof(FontMetrics) == 148, "Sizeof font metrics is incorrect");
+ uint32_t rom_fontroot = mem_read_32(MAP::ROM_FONT_ADDR);
+ mem_read_bulk(rom_fontroot + 148 * (font - 16), (uint8_t*) this, 148);
+}
+
+uint16_t CLCD::FontMetrics::get_text_width(const char *str, size_t n) const {
+ uint16_t width = 0;
+ const uint8_t *p = (const uint8_t *) str;
+ for (;;) {
+ const uint8_t val = *p++; n--;
+ if (!val || n == 0) break;
+ width += val < 128 ? char_widths[val] : 0;
+ }
+ return width;
+}
+
+uint16_t CLCD::FontMetrics::get_text_width(FSTR_P str, size_t n) const {
+ uint16_t width = 0;
+ const uint8_t *p = (const uint8_t *) str;
+ for (;;) {
+ const uint8_t val = pgm_read_byte(p++); n--;
+ if (!val || n == 0) break;
+ width += val < 128 ? char_widths[val] : 0;
+ }
+ return width;
+}
+
+/************************** HOST COMMAND FUNCTION *********************************/
+
+void CLCD::host_cmd(unsigned char host_command, unsigned char byte2) { // Sends 24-Bit Host Command to LCD
+ if (host_command != FTDI::ACTIVE) {
+ host_command |= 0x40;
+ }
+ spi_ftdi_select();
+ spi_send(host_command);
+ spi_send(byte2);
+ spi_send(0x00);
+ spi_ftdi_deselect();
+}
+
+/************************** MEMORY READ FUNCTIONS *********************************/
+
+void CLCD::spi_read_addr(uint32_t reg_address) {
+ spi_send((reg_address >> 16) & 0x3F); // Address [21:16]
+ spi_send((reg_address >> 8 ) & 0xFF); // Address [15:8]
+ spi_send((reg_address >> 0) & 0xFF); // Address [7:0]
+ spi_send(0x00); // Dummy Byte
+}
+
+// Write 4-Byte Address, Read Multiple Bytes
+void CLCD::mem_read_bulk(uint32_t reg_address, uint8_t *data, uint16_t len) {
+ spi_ftdi_select();
+ spi_read_addr(reg_address);
+ spi_read_bulk (data, len);
+ spi_ftdi_deselect();
+}
+
+// Write 4-Byte Address, Read 1-Byte Data
+uint8_t CLCD::mem_read_8(uint32_t reg_address) {
+ spi_ftdi_select();
+ spi_read_addr(reg_address);
+ uint8_t r_data = spi_read_8();
+ spi_ftdi_deselect();
+ return r_data;
+}
+
+// Write 4-Byte Address, Read 2-Bytes Data
+uint16_t CLCD::mem_read_16(uint32_t reg_address) {
+ using namespace SPI::least_significant_byte_first;
+ spi_ftdi_select();
+ spi_read_addr(reg_address);
+ uint16_t r_data = spi_read_16();
+ spi_ftdi_deselect();
+ return r_data;
+}
+
+// Write 4-Byte Address, Read 4-Bytes Data
+uint32_t CLCD::mem_read_32(uint32_t reg_address) {
+ using namespace SPI::least_significant_byte_first;
+ spi_ftdi_select();
+ spi_read_addr(reg_address);
+ uint32_t r_data = spi_read_32();
+ spi_ftdi_deselect();
+ return r_data;
+}
+
+/************************** MEMORY WRITE FUNCTIONS *********************************/
+
+// Generic operations for transforming a byte, for use with _mem_write_bulk:
+static inline uint8_t reverse_byte(uint8_t a) {
+ return ((a & 0x1) << 7) | ((a & 0x2) << 5) |
+ ((a & 0x4) << 3) | ((a & 0x8) << 1) |
+ ((a & 0x10) >> 1) | ((a & 0x20) >> 3) |
+ ((a & 0x40) >> 5) | ((a & 0x80) >> 7);
+}
+static inline uint8_t xbm_write(const uint8_t *p) {return reverse_byte(pgm_read_byte(p));}
+
+void CLCD::spi_write_addr(uint32_t reg_address) {
+ spi_send((reg_address >> 16) | 0x80); // Address [21:16]
+ spi_send((reg_address >> 8 ) & 0xFF); // Address [15:8]
+ spi_send((reg_address >> 0) & 0xFF); // Address [7:0]
+}
+
+// Write 3-Byte Address, Multiple Bytes, plus padding bytes, from RAM
+void CLCD::mem_write_bulk(uint32_t reg_address, const void *data, uint16_t len, uint8_t padding) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_bulk(data, len, padding);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Multiple Bytes, plus padding bytes, from PROGMEM
+void CLCD::mem_write_bulk(uint32_t reg_address, FSTR_P str, uint16_t len, uint8_t padding) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_bulk(str, len, padding);
+ spi_ftdi_deselect();
+}
+
+ // Write 3-Byte Address, Multiple Bytes, plus padding bytes, from PROGMEM
+void CLCD::mem_write_pgm(uint32_t reg_address, const void *data, uint16_t len, uint8_t padding) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_bulk(data, len, padding);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Multiple Bytes, plus padding bytes, from PROGMEM, reversing bytes (suitable for loading XBM images)
+void CLCD::mem_write_xbm(uint32_t reg_address, FSTR_P data, uint16_t len, uint8_t padding) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_bulk(data, len, padding);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Write 1-Byte Data
+void CLCD::mem_write_8(uint32_t reg_address, uint8_t data) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_8(data);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Write 2-Bytes Data
+void CLCD::mem_write_16(uint32_t reg_address, uint16_t data) {
+ using namespace SPI::least_significant_byte_first;
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_16(data);
+ spi_ftdi_deselect();
+}
+
+// Write 3-Byte Address, Write 4-Bytes Data
+void CLCD::mem_write_32(uint32_t reg_address, uint32_t data) {
+ using namespace SPI::least_significant_byte_first;
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ spi_write_32(data);
+ spi_ftdi_deselect();
+}
+
+// Fill area of len size with repeated data bytes
+void CLCD::mem_write_fill(uint32_t reg_address, uint8_t data, uint16_t len) {
+ spi_ftdi_select();
+ spi_write_addr(reg_address);
+ while (len--) spi_write_8(data);
+ spi_ftdi_deselect();
+}
+
+/******************* FT800/810 Co-processor Commands *********************************/
+
+#if FTDI_API_LEVEL == 800
+uint32_t CLCD::CommandFifo::command_write_ptr = 0xFFFFFFFFul;
+#endif
+
+void CLCD::CommandFifo::cmd(uint32_t cmd32) {
+ write((void*)&cmd32, sizeof(uint32_t));
+}
+
+void CLCD::CommandFifo::cmd(void *data, uint16_t len) {
+ write(data, len);
+}
+
+void CLCD::CommandFifo::bgcolor(uint32_t rgb) {
+ cmd(CMD_BGCOLOR);
+ cmd(rgb);
+}
+
+void CLCD::CommandFifo::fgcolor(uint32_t rgb) {
+ cmd(CMD_FGCOLOR);
+ cmd(rgb);
+}
+
+void CLCD::CommandFifo::gradcolor(uint32_t rgb) {
+ cmd(CMD_GRADCOLOR);
+ cmd(rgb);
+}
+
+// This sends the a text command to the command preprocessor, must be followed by str()
+void CLCD::CommandFifo::button(int16_t x, int16_t y, int16_t w, int16_t h, int16_t font, uint16_t option) {
+ struct {
+ int32_t type = CMD_BUTTON;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ int16_t font;
+ uint16_t option;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.font = font;
+ cmd_data.option = option;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+// This sends the a text command to the command preprocessor, must be followed by str()
+void CLCD::CommandFifo::text(int16_t x, int16_t y, int16_t font, uint16_t options) {
+ struct {
+ int32_t type = CMD_TEXT;
+ int16_t x;
+ int16_t y;
+ int16_t font;
+ uint16_t options;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.font = font;
+ cmd_data.options = options;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+// This sends the a toggle command to the command preprocessor, must be followed by str()
+void CLCD::CommandFifo::toggle(int16_t x, int16_t y, int16_t w, int16_t font, uint16_t options, bool state) {
+ struct {
+ int32_t type = CMD_TOGGLE;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t font;
+ uint16_t options;
+ uint16_t state;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.font = font;
+ cmd_data.options = options;
+ cmd_data.state = state ? 65535 : 0;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+// This sends the a keys command to the command preprocessor, must be followed by str()
+void CLCD::CommandFifo::keys(int16_t x, int16_t y, int16_t w, int16_t h, int16_t font, uint16_t options) {
+ struct {
+ int32_t type = CMD_KEYS;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ int16_t font;
+ uint16_t options;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.font = font;
+ cmd_data.options = options;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::clock(int16_t x, int16_t y, int16_t r, uint16_t options, int16_t h, int16_t m, int16_t s, int16_t ms)
+{
+ struct {
+ int32_t type = CMD_CLOCK;
+ int16_t x;
+ int16_t y;
+ int16_t r;
+ uint16_t options;
+ int16_t h;
+ int16_t m;
+ int16_t s;
+ int16_t ms;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.r = r;
+ cmd_data.options = options;
+ cmd_data.h = h;
+ cmd_data.m = m;
+ cmd_data.s = s;
+ cmd_data.ms = ms;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::gauge(int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t major, uint16_t minor, uint16_t val, uint16_t range)
+{
+ struct {
+ int32_t type = CMD_GAUGE;
+ int16_t x;
+ int16_t y;
+ int16_t r;
+ uint16_t options;
+ uint16_t major;
+ uint16_t minor;
+ uint16_t val;
+ uint16_t range;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.r = r;
+ cmd_data.options = options;
+ cmd_data.major = major;
+ cmd_data.minor = minor;
+ cmd_data.val = val;
+ cmd_data.range = range;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::dial(int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t val)
+{
+ struct {
+ int32_t type = CMD_DIAL;
+ int16_t x;
+ int16_t y;
+ int16_t r;
+ uint16_t options;
+ uint16_t val;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.r = r;
+ cmd_data.options = options;
+ cmd_data.val = val;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::scrollbar(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t size, uint16_t range) {
+ struct {
+ int32_t type = CMD_SCROLLBAR;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ uint16_t h;
+ uint16_t options;
+ uint16_t val;
+ uint16_t size;
+ uint16_t range;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.options = options;
+ cmd_data.val = val;
+ cmd_data.size = size;
+ cmd_data.range = range;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::progress(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t range) {
+ struct {
+ int32_t type = CMD_PROGRESS;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ uint16_t options;
+ uint16_t val;
+ uint16_t range;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.options = options;
+ cmd_data.val = val;
+ cmd_data.range = range;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::slider(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t range) {
+ struct {
+ int32_t type = CMD_SLIDER;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ uint16_t options;
+ uint16_t val;
+ uint16_t range;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.options = options;
+ cmd_data.val = val;
+ cmd_data.range = range;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::gradient(int16_t x0, int16_t y0, uint32_t rgb0, int16_t x1, int16_t y1, uint32_t rgb1) {
+ struct {
+ int32_t type = CMD_GRADIENT;
+ int16_t x0;
+ int16_t y0;
+ uint32_t rgb0;
+ int16_t x1;
+ int16_t y1;
+ uint32_t rgb1;
+ } cmd_data;
+
+ cmd_data.x0 = x0;
+ cmd_data.y0 = y0;
+ cmd_data.rgb0 = rgb0;
+ cmd_data.x1 = x1;
+ cmd_data.y1 = y1;
+ cmd_data.rgb1 = rgb1;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::number(int16_t x, int16_t y, int16_t font, uint16_t options, int32_t n) {
+ struct {
+ int32_t type = CMD_NUMBER;
+ int16_t x;
+ int16_t y;
+ int16_t font;
+ uint16_t options;
+ int16_t n;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.font = font;
+ cmd_data.options = options;
+ cmd_data.n = n;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memzero(uint32_t ptr, uint32_t size) {
+ struct {
+ uint32_t type = CMD_MEMZERO;
+ uint32_t ptr;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memset(uint32_t ptr, uint32_t val, uint32_t size) {
+ struct {
+ uint32_t type = CMD_MEMSET;
+ uint32_t ptr;
+ uint32_t val;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.val = val;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memcpy(uint32_t dst, uint32_t src, uint32_t size) {
+ struct {
+ uint32_t type = CMD_MEMCPY;
+ uint32_t dst;
+ uint32_t src;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.dst = dst;
+ cmd_data.src = src;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memcrc(uint32_t ptr, uint32_t num, uint32_t result) {
+ struct {
+ uint32_t type = CMD_MEMCRC;
+ uint32_t ptr;
+ uint32_t num;
+ uint32_t result;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.num = num;
+ cmd_data.result = result;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::memwrite(uint32_t ptr, uint32_t value) {
+ struct {
+ uint32_t type = CMD_MEMWRITE;
+ uint32_t ptr;
+ uint32_t num;
+ uint32_t value;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.num = 4;
+ cmd_data.value = value;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::append(uint32_t ptr, uint32_t size) {
+ struct {
+ uint32_t type = CMD_APPEND;
+ uint32_t ptr;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::inflate(uint32_t ptr) {
+ struct {
+ uint32_t type = CMD_INFLATE;
+ uint32_t ptr;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::getptr(uint32_t result) {
+ struct {
+ uint32_t type = CMD_GETPTR;
+ uint32_t result;
+ } cmd_data;
+
+ cmd_data.result = result;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::track(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t tag) {
+ struct {
+ uint32_t type = CMD_TRACK;
+ int16_t x;
+ int16_t y;
+ int16_t w;
+ int16_t h;
+ int16_t tag;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.tag = tag;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::sketch(int16_t x, int16_t y, uint16_t w, uint16_t h, uint32_t ptr, uint16_t format) {
+ struct {
+ uint32_t type = CMD_SKETCH;
+ int16_t x;
+ int16_t y;
+ uint16_t w;
+ uint16_t h;
+ uint32_t ptr;
+ uint16_t format;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.ptr = ptr;
+ cmd_data.format = format;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::snapshot(uint32_t ptr) {
+ struct {
+ uint32_t type = CMD_SNAPSHOT;
+ uint32_t ptr;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::spinner(int16_t x, int16_t y, uint16_t style, uint16_t scale) {
+ struct {
+ uint32_t type = CMD_SPINNER;
+ uint16_t x;
+ uint16_t y;
+ uint16_t style;
+ uint16_t scale;
+ } cmd_data;
+
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.style = style;
+ cmd_data.scale = scale;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::loadimage(uint32_t ptr, uint32_t options) {
+ struct {
+ uint32_t type = CMD_LOADIMAGE;
+ uint32_t ptr;
+ uint32_t options;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.options = options;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::getprops(uint32_t ptr, uint32_t width, uint32_t height) {
+ struct {
+ uint32_t type = CMD_GETPROPS;
+ uint32_t ptr;
+ uint32_t width;
+ uint32_t height;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.width = width;
+ cmd_data.height = height;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::scale(int32_t sx, int32_t sy) {
+ struct {
+ uint32_t type = CMD_SCALE;
+ int32_t sx;
+ int32_t sy;
+ } cmd_data;
+
+ cmd_data.sx = sx;
+ cmd_data.sy = sy;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::rotate(int32_t a) {
+ struct {
+ uint32_t type = CMD_ROTATE;
+ int32_t a;
+ } cmd_data;
+
+ cmd_data.a = a;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+void CLCD::CommandFifo::translate(int32_t tx, int32_t ty) {
+ struct {
+ uint32_t type = CMD_TRANSLATE;
+ int32_t tx;
+ int32_t ty;
+ } cmd_data;
+
+ cmd_data.tx = tx;
+ cmd_data.ty = ty;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::setbase(uint8_t base) {
+ struct {
+ int32_t type = CMD_SETBASE;
+ uint32_t base;
+ } cmd_data;
+
+ cmd_data.base = base;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::setbitmap(uint32_t addr, uint16_t fmt, uint16_t w, uint16_t h) {
+ struct {
+ uint32_t type = CMD_SETBITMAP;
+ uint32_t addr;
+ uint16_t fmt;
+ uint16_t w;
+ uint16_t h;
+ uint16_t dummy;
+ } cmd_data;
+
+ cmd_data.addr = addr;
+ cmd_data.fmt = fmt;
+ cmd_data.w = w;
+ cmd_data.h = h;
+ cmd_data.dummy = 0;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::snapshot2(uint32_t format, uint32_t ptr, int16_t x, int16_t y, uint16_t w, uint16_t h) {
+ struct {
+ uint32_t type = CMD_SNAPSHOT2;
+ uint32_t format;
+ uint32_t ptr;
+ int16_t x;
+ int16_t y;
+ uint16_t w;
+ uint16_t h;
+ } cmd_data;
+
+ cmd_data.format = format;
+ cmd_data.ptr = ptr;
+ cmd_data.x = x;
+ cmd_data.y = y;
+ cmd_data.w = w;
+ cmd_data.h = h;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::mediafifo(uint32_t ptr, uint32_t size) {
+ struct {
+ uint32_t type = CMD_MEDIAFIFO;
+ uint32_t ptr;
+ uint32_t size;
+ } cmd_data;
+
+ cmd_data.ptr = ptr;
+ cmd_data.size = size;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::videostart() {
+ cmd( CMD_VIDEOSTART );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::videoframe(uint32_t dst, uint32_t ptr) {
+ struct {
+ uint32_t type = CMD_VIDEOFRAME;
+ uint32_t dst;
+ uint32_t ptr;
+ } cmd_data;
+
+ cmd_data.dst = dst;
+ cmd_data.ptr = ptr;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::playvideo(uint32_t options) {
+ struct {
+ uint32_t type = CMD_PLAYVIDEO;
+ uint32_t options;
+ } cmd_data;
+
+ cmd_data.options = options;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::setrotate(uint8_t rotation) {
+ struct {
+ uint32_t type = CMD_SETROTATE;
+ uint32_t rotation;
+ } cmd_data;
+
+ cmd_data.rotation = rotation;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+#if FTDI_API_LEVEL >= 810
+void CLCD::CommandFifo::romfont(uint8_t font, uint8_t romslot) {
+ struct {
+ uint32_t type = CMD_ROMFONT;
+ uint32_t font;
+ uint32_t romslot;
+ } cmd_data;
+
+ cmd_data.font = font;
+ cmd_data.romslot = romslot;
+
+ cmd( &cmd_data, sizeof(cmd_data) );
+}
+#endif
+
+/**************************** FT800/810 Co-Processor Command FIFO ****************************/
+
+bool CLCD::CommandFifo::is_processing() {
+ return (mem_read_32(REG::CMD_READ) & 0x0FFF) != (mem_read_32(REG::CMD_WRITE) & 0x0FFF);
+}
+
+bool CLCD::CommandFifo::has_fault() {
+ uint16_t Cmd_Read_Reg = mem_read_32(REG::CMD_READ) & 0x0FFF;
+ return Cmd_Read_Reg == 0x0FFF;
+}
+
+#if FTDI_API_LEVEL == 800
+
+void CLCD::CommandFifo::start() {
+ if (command_write_ptr == 0xFFFFFFFFul) {
+ command_write_ptr = mem_read_32(REG::CMD_WRITE) & 0x0FFF;
+ }
+}
+
+void CLCD::CommandFifo::execute() {
+ if (command_write_ptr != 0xFFFFFFFFul) {
+ mem_write_32(REG::CMD_WRITE, command_write_ptr);
+ }
+}
+
+void CLCD::CommandFifo::reset() {
+ safe_delay(100);
+ mem_write_32(REG::CPURESET, 0x00000001);
+ mem_write_32(REG::CMD_WRITE, 0x00000000);
+ mem_write_32(REG::CMD_READ, 0x00000000);
+ mem_write_32(REG::CPURESET, 0x00000000);
+ safe_delay(300);
+ command_write_ptr = 0xFFFFFFFFul;
+};
+
+template bool CLCD::CommandFifo::_write_unaligned(T data, uint16_t len) {
+ const char *ptr = (const char*)data;
+ uint32_t bytes_tail, bytes_head;
+ uint32_t command_read_ptr;
+
+ #if ENABLED(TOUCH_UI_DEBUG)
+ if (command_write_ptr == 0xFFFFFFFFul)
+ SERIAL_ECHO_MSG("Attempt to write to FIFO before CommandFifo::Cmd_Start().");
+ #endif
+
+ /* Wait until there is enough space in the circular buffer for the transfer */
+ do {
+ command_read_ptr = mem_read_32(REG::CMD_READ) & 0x0FFF;
+ if (command_read_ptr <= command_write_ptr) {
+ bytes_tail = 4096U - command_write_ptr;
+ bytes_head = command_read_ptr;
+ }
+ else {
+ bytes_tail = command_read_ptr - command_write_ptr;
+ bytes_head = 0;
+ }
+ // Check for faults which can lock up the command processor
+ if (has_fault()) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("Fault waiting for space in the command processor");
+ #endif
+ return false;
+ }
+ } while ((bytes_tail + bytes_head) < len);
+
+ /* Write as many bytes as possible following REG::CMD_WRITE */
+ uint16_t bytes_to_write = min(len, bytes_tail);
+ mem_write_bulk (MAP::RAM_CMD + command_write_ptr, T(ptr), bytes_to_write);
+ command_write_ptr += bytes_to_write;
+ ptr += bytes_to_write;
+ len -= bytes_to_write;
+
+ if (len > 0) {
+ /* Write remaining bytes at start of circular buffer */
+ mem_write_bulk (MAP::RAM_CMD, T(ptr), len);
+ command_write_ptr = len;
+ }
+
+ if (command_write_ptr == 4096U) {
+ command_write_ptr = 0;
+ }
+ return true;
+}
+
+// Writes len bytes into the FIFO, if len is not
+// divisible by four, zero bytes will be written
+// to align to the boundary.
+
+template bool CLCD::CommandFifo::write(T data, uint16_t len) {
+ const uint8_t padding = MULTIPLE_OF_4(len) - len;
+ const uint8_t pad_bytes[] = { 0, 0, 0, 0 };
+ return _write_unaligned(data, len) &&
+ _write_unaligned(pad_bytes, padding);
+}
+
+#else // FTDI_API_LEVEL != 800 ...
+
+void CLCD::CommandFifo::start() {
+}
+
+void CLCD::CommandFifo::execute() {
+}
+
+void CLCD::CommandFifo::reset() {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("Resetting command processor");
+ #endif
+ safe_delay(100);
+ mem_write_32(REG::CPURESET, 0x00000001);
+ mem_write_32(REG::CMD_WRITE, 0x00000000);
+ mem_write_32(REG::CMD_READ, 0x00000000);
+ mem_write_32(REG::CPURESET, 0x00000000);
+ safe_delay(300);
+};
+
+// Writes len bytes into the FIFO, if len is not
+// divisible by four, zero bytes will be written
+// to align to the boundary.
+
+template bool CLCD::CommandFifo::write(T data, uint16_t len) {
+ const uint8_t padding = MULTIPLE_OF_4(len) - len;
+
+ if (has_fault()) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("Faulted... ignoring write.");
+ #endif
+ return false;
+ }
+ // The FT810 provides a special register that can be used
+ // for writing data without us having to do our own FIFO
+ // management.
+ uint16_t Command_Space = mem_read_32(REG::CMDB_SPACE) & 0x0FFF;
+ if (Command_Space < (len + padding)) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Waiting for ", len + padding, " bytes in command queue, now free: ", Command_Space);
+ #endif
+ do {
+ Command_Space = mem_read_32(REG::CMDB_SPACE) & 0x0FFF;
+ if (has_fault()) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("... fault");
+ #endif
+ return false;
+ }
+ } while (Command_Space < len + padding);
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("... done");
+ #endif
+ }
+ mem_write_bulk(REG::CMDB_WRITE, data, len, padding);
+ return true;
+}
+
+#endif // ... FTDI_API_LEVEL != 800
+
+template bool CLCD::CommandFifo::write(const void*, uint16_t);
+template bool CLCD::CommandFifo::write(FSTR_P, uint16_t);
+
+// CO_PROCESSOR COMMANDS
+
+void CLCD::CommandFifo::str(const char * data, size_t maxlen) {
+ // Write the string without the terminating '\0'
+ const size_t len = strnlen(data, maxlen);
+ write(data, len);
+
+ // If padding was added by the previous write, then
+ // the string is terminated. Otherwise write four
+ // more zeros.
+ const uint8_t padding = MULTIPLE_OF_4(len) - len;
+ if (padding == 0) {
+ const uint8_t pad_bytes[] = {0, 0, 0, 0};
+ write(pad_bytes, 4);
+ }
+}
+
+void CLCD::CommandFifo::str(const char * data) {
+ write(data, strlen(data)+1);
+}
+
+void CLCD::CommandFifo::str(FSTR_P data) {
+ write(data, strlen_P((const char*)data)+1);
+}
+
+/******************* LCD INITIALIZATION ************************/
+
+void CLCD::init() {
+ spi_init(); // Set Up I/O Lines for SPI and FT800/810 Control
+ ftdi_reset(); // Power down/up the FT8xx with the appropriate delays
+
+ host_cmd(Use_Crystal ? CLKEXT : CLKINT, 0);
+ host_cmd(FTDI::ACTIVE, 0); // Activate the System Clock
+
+ delay(40); // FTDI/BRT recommendation: no SPI traffic during startup. EVE needs at the very least 45ms to start, so leave her alone for a little while.
+
+ /* read the device-id until it returns 0x7C or times out, should take less than 150ms */
+ uint8_t counter;
+ for (counter = 0; counter < 250; counter++) {
+ uint8_t device_id = mem_read_8(REG::ID); // Read Device ID, Should Be 0x7C;
+ if (device_id == 0x7C) {
+ if (ENABLED(TOUCH_UI_DEBUG)) SERIAL_ECHO_MSG("FTDI chip initialized ");
+ break;
+ }
+ else
+ delay(1);
+
+ if (TERN0(TOUCH_UI_DEBUG, counter > 248))
+ SERIAL_ECHO_MSG("Timeout waiting for device ID, should be 124, got ", device_id);
+ }
+
+ /* Ensure all units are in working condition, usually the touch-controller needs a little more time */
+ for (counter = 0; counter < 100; counter++) {
+ uint8_t reset_status = mem_read_8(REG::CPURESET) & 0x03;
+ if (reset_status == 0x00) {
+ if (ENABLED(TOUCH_UI_DEBUG)) SERIAL_ECHO_MSG("FTDI chip all units running ");
+ break;
+ }
+ else
+ delay(1);
+
+ if (TERN0(TOUCH_UI_DEBUG, counter > 98))
+ SERIAL_ECHO_MSG("Timeout waiting for reset status. Should be 0x00, got ", reset_status);
+ }
+
+ #if ENABLED(USE_GT911) /* switch BT815 to use Goodix GT911 touch controller */
+ mem_write_32(REG::TOUCH_CONFIG, 0x000005D1);
+ #endif
+
+ #if ENABLED(PATCH_GT911) /* patch FT813 use Goodix GT911 touch controller */
+ mem_write_pgm(REG::CMDB_WRITE, GT911_data, sizeof(GT911_data)); /* write binary blob to command-fifo */
+ delay(10);
+ mem_write_8(REG::TOUCH_OVERSAMPLE, 0x0F); /* setup oversample to 0x0f as "hidden" in binary-blob for AN_336 */
+ mem_write_16(REG::TOUCH_CONFIG, 0x05d0); /* write magic cookie as requested by AN_336 */
+
+ /* specific to the EVE2 modules from Matrix-Orbital we have to use GPIO3 to reset GT911 */
+ mem_write_16(REG::GPIOX_DIR,0x8008); /* Reset-Value is 0x8000, adding 0x08 sets GPIO3 to output, default-value for REG_GPIOX is 0x8000 -> Low output on GPIO3 */
+ delay(1); /* wait more than 100µs */
+ mem_write_8(REG::CPURESET, 0x00); /* clear all resets */
+ delay(56); /* wait more than 55ms */
+ mem_write_16(REG::GPIOX_DIR,0x8000); /* setting GPIO3 back to input */
+ #endif
+
+ mem_write_8(REG::PWM_DUTY, 0); // turn off Backlight, Frequency already is set to 250Hz default
+
+ /* Configure the FT8xx Registers */
+ mem_write_16(REG::HCYCLE, FTDI::Hcycle);
+ mem_write_16(REG::HOFFSET, FTDI::Hoffset);
+ mem_write_16(REG::HSYNC0, FTDI::Hsync0);
+ mem_write_16(REG::HSYNC1, FTDI::Hsync1);
+ mem_write_16(REG::VCYCLE, FTDI::Vcycle);
+ mem_write_16(REG::VOFFSET, FTDI::Voffset);
+ mem_write_16(REG::VSYNC0, FTDI::Vsync0);
+ mem_write_16(REG::VSYNC1, FTDI::Vsync1);
+ mem_write_16(REG::HSIZE, FTDI::Hsize);
+ mem_write_16(REG::VSIZE, FTDI::Vsize);
+ mem_write_8(REG::SWIZZLE, FTDI::Swizzle);
+ mem_write_8(REG::PCLK_POL, FTDI::Pclkpol);
+ mem_write_8(REG::CSPREAD, FTDI::CSpread);
+
+ /* write a basic display-list to get things started */
+ mem_write_32(MAP::RAM_DL, DL::CLEAR_COLOR_RGB);
+ mem_write_32(MAP::RAM_DL + 4, (DL::CLEAR | 0x07)); /* clear color, stencil and tag buffer */
+ mem_write_32(MAP::RAM_DL + 8, DL::DL_DISPLAY); /* end of display list */
+
+ mem_write_8(REG::DLSWAP, 0x02); // activate display list, Bad Magic Cookie 2 = switch to new list after current frame is scanned out
+
+ //mem_write_8(REG::TOUCH_MODE, 0x03); // Configure the Touch Screen, Bad Magic Cookie, 3 = CONTINUOUS = Reset Default
+ //mem_write_8(REG::TOUCH_ADC_MODE, 0x01); // Bad Magic Cookie, 1 = single touch = Reset Default
+ //mem_write_8(REG::TOUCH_OVERSAMPLE, 0x0F); // Reset Default = 7 - why 15?
+ mem_write_16(REG::TOUCH_RZTHRESH, touch_threshold); /* setup touch sensitivity */
+ mem_write_8(REG::VOL_SOUND, 0x00); // Turn Synthesizer Volume Off
+
+ /* turn on the display by setting DISP high */
+ /* turn on the Audio Amplifier by setting GPIO_1 high for the select few modules supporting this */
+ /* no need to use GPIOX here since DISP/GPIO_0 and GPIO_1 are on REG::GPIO for FT81x as well */
+ if (GPIO_1_Audio_Shutdown) {
+ mem_write_8(REG::GPIO_DIR, GPIO_DISP | GPIO_GP1);
+ mem_write_8(REG::GPIO, GPIO_DISP | GPIO_GP1);
+ }
+ else if (GPIO_0_Audio_Enable) {
+ mem_write_8(REG::GPIO_DIR, GPIO_DISP | GPIO_GP0);
+ mem_write_8(REG::GPIO, GPIO_DISP | GPIO_GP0);
+ }
+ else
+ mem_write_8(REG::GPIO, GPIO_DISP); /* REG::GPIO_DIR is set to output for GPIO_DISP by default */
+
+ mem_write_8(REG::PCLK, Pclk); // Turns on Clock by setting PCLK Register to the value necessary for the module
+
+ mem_write_16(REG::PWM_HZ, 0x00FA);
+
+ // Turning off dithering seems to help prevent horizontal line artifacts on certain colors
+ mem_write_8(REG::DITHER, 0);
+
+ default_touch_transform();
+ default_display_orientation();
+}
+
+void CLCD::default_touch_transform() {
+ // Set Initial Values for Touch Transform Registers
+ mem_write_32(REG::ROTATE, 0);
+ mem_write_32(REG::TOUCH_TRANSFORM_A, FTDI::default_transform_a);
+ mem_write_32(REG::TOUCH_TRANSFORM_B, FTDI::default_transform_b);
+ mem_write_32(REG::TOUCH_TRANSFORM_C, FTDI::default_transform_c);
+ mem_write_32(REG::TOUCH_TRANSFORM_D, FTDI::default_transform_d);
+ mem_write_32(REG::TOUCH_TRANSFORM_E, FTDI::default_transform_e);
+ mem_write_32(REG::TOUCH_TRANSFORM_F, FTDI::default_transform_f);
+}
+
+void CLCD::default_display_orientation() {
+ #if FTDI_API_LEVEL >= 810
+ // Set the initial display orientation. On the FT810, we use the command
+ // processor to do this since it will also update the transform matrices.
+ CommandFifo cmd;
+ cmd.setrotate(
+ ENABLED(TOUCH_UI_MIRRORED) * 4
+ + ENABLED(TOUCH_UI_PORTRAIT) * 2
+ + ENABLED(TOUCH_UI_INVERTED) * 1
+ );
+ cmd.execute();
+ #elif EITHER(TOUCH_UI_PORTRAIT, TOUCH_UI_MIRRORED)
+ #error "PORTRAIT or MIRRORED orientation not supported on the FT800."
+ #elif ENABLED(TOUCH_UI_INVERTED)
+ mem_write_32(REG::ROTATE, 1);
+ #endif
+}
+
+#endif // FTDI_BASIC
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h
new file mode 100644
index 0000000..2e2657a
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h
@@ -0,0 +1,263 @@
+/****************
+ * commands.cpp *
+ ****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+ /****************************************************************************
+ * FUNCTION MAP *
+ * *
+ * SPI and FT800/810 Commands *
+ * *
+ * CLCD::spi_select() Set CS line to 0 *
+ * CLCD::spi_deselect() Set CS Line to 1 *
+ * CLCD::reset() Toggle FT800/810 Power Down Line 50 ms *
+ * CLCD::spi_init() Configure I/O Lines for SPI *
+ * CLCD::spi_transfer() Send/Receive 1 SPI Byte *
+ * CLCD::init() Set FT800/810 Registers *
+ * CLCD::enable() Turn On FT800/810 PCLK *
+ * CLCD::disable() Turn Off FT8880/810 PCLK *
+ * CLCD::set_backlight() Set LCD Backlight Level *
+ * *
+ * MEMORY READ FUNCTIONS *
+ * *
+ * CLCD::mem_read_addr() Send 32-Bit Address *
+ * CLCD::mem_read_8() Read 1 Byte *
+ * CLCD::mem_read_16() Read 2 Bytes *
+ * CLCD::mem_read_32() Read 4 Bytes *
+ * *
+ * MEMORY WRITE FUNCTIONS *
+ * *
+ * CLCD::mem_write_addr() Send 24-Bit Address *
+ * CLCD::mem_write_8() Write 1 Byte *
+ * CLCD::mem_write_16() Write 2 Bytes *
+ * CLCD::mem_write_32() Write 4 Bytes *
+ * *
+ * HOST COMMAND FUNCTION *
+ * *
+ * CLCD::host_cmd() Send 24-Bit Host Command *
+ * *
+ * COMMAND BUFFER FUNCTIONS *
+ * *
+ * CLCD::cmd() Send 32-Bit Value(4 Bytes)CMD Buffer *
+ * CLCD::cmd() Send Data Structure with 32-Bit Cmd *
+ * CLCD::str() Send Text String in 32-Bit Multiples *
+
+ * *
+ * FT800/810 GRAPHIC COMMANDS *
+ * *
+ * class CLCD:CommandFifo {} Class to control Cmd FIFO *
+
+ * CommandFifo::start() Wait for CP finish - Set FIFO Ptr *
+ * CommandFifo::execute() Set REG_CMD_WRITE and start CP *
+ * CommandFifo::reset() Set Cmd Buffer Pointers to 0 *
+ *
+ * CommandFifo::fgcolor Set Graphic Item Foreground Color *
+ * CommandFifo::bgcolor Set Graphic Item Background Color *
+ * CommandFifo::begin() Begin Drawing a Primitive *
+ * CommandFifo::mem_copy() Copy a Block of Memory *
+ * CommandFifo::append() Append Commands to Current DL *
+ * CommandFifo::gradient_color() Set 3D Button Highlight Color *
+ * CommandFifo::button() Draw Button with Bulk Write *
+ * CommandFifo::text() Draw Text with Bulk Write *
+ *****************************************************************************/
+
+ /**************************************************
+ * RAM_G Graphics RAM Allocation *
+ * *
+ * Address Use *
+ * *
+ * 8000 Extruder Bitmap *
+ * 8100 Bed Heat Bitmap *
+ * 8200 Fan Bitmap *
+ * 8300 Thumb Drive Symbol Bitmap *
+ * 35000 Static DL Space (FT800) *
+ * F5000 Static DL Space (FT810) *
+ **************************************************/
+
+#pragma once
+
+typedef const __FlashStringHelper *FSTR_P;
+
+class UIStorage;
+
+class CLCD {
+ friend class UIStorage;
+
+ public:
+ typedef FTDI::ftdi_registers REG;
+ typedef FTDI::ftdi_memory_map MAP;
+
+ static void spi_write_addr (uint32_t reg_address);
+ static void spi_read_addr (uint32_t reg_address);
+
+ static uint8_t mem_read_8 (uint32_t reg_address);
+ static uint16_t mem_read_16 (uint32_t reg_address);
+ static uint32_t mem_read_32 (uint32_t reg_address);
+ static void mem_read_bulk (uint32_t reg_address, uint8_t *data, uint16_t len);
+
+ static void mem_write_8 (uint32_t reg_address, uint8_t w_data);
+ static void mem_write_16 (uint32_t reg_address, uint16_t w_data);
+ static void mem_write_32 (uint32_t reg_address, uint32_t w_data);
+ static void mem_write_fill (uint32_t reg_address, uint8_t w_data, uint16_t len);
+ static void mem_write_bulk (uint32_t reg_address, const void *data, uint16_t len, uint8_t padding = 0);
+ static void mem_write_pgm (uint32_t reg_address, const void *data, uint16_t len, uint8_t padding = 0);
+ static void mem_write_bulk (uint32_t reg_address, FSTR_P str, uint16_t len, uint8_t padding = 0);
+ static void mem_write_xbm (uint32_t reg_address, FSTR_P str, uint16_t len, uint8_t padding = 0);
+
+ public:
+ class CommandFifo;
+ class FontMetrics;
+
+ static void init();
+ static void default_touch_transform();
+ static void default_display_orientation();
+ static void turn_on_backlight();
+ static void enable();
+ static void disable();
+ static void set_brightness (uint8_t brightness);
+ static uint8_t get_brightness();
+ static void host_cmd (unsigned char host_command, unsigned char byte2);
+ static uint32_t dl_size() {return CLCD::mem_read_32(REG::CMD_DL) & 0x1FFF;}
+
+ static void get_font_metrics (uint8_t font, struct FontMetrics &fm);
+ static uint16_t get_text_width(const uint8_t font, const char *str);
+ static uint16_t get_text_width_P(const uint8_t font, const char *str);
+
+ static uint8_t get_tag () {return mem_read_8(REG::TOUCH_TAG);}
+ static bool is_touching () {return (mem_read_32(REG::TOUCH_DIRECT_XY) & 0x80000000) == 0;}
+
+ static uint8_t get_tracker (uint16_t &value) {
+ uint32_t tracker = mem_read_32(REG::TRACKER);
+ value = tracker >> 16;
+ return tracker & 0xFF;
+ }
+};
+
+/*************************** FT800/810 Font Metrics ****************************/
+
+class CLCD::FontMetrics {
+ public:
+ uint8_t char_widths[128];
+ uint32_t format;
+ uint32_t stride;
+ uint32_t width;
+ uint32_t height;
+ uint32_t ptr;
+
+ FontMetrics() {}
+ FontMetrics(uint8_t font) {load(font);}
+
+ void load(uint8_t font);
+
+ // Returns width of string, up to a maximum of n characters.
+ uint16_t get_text_width(const char *str, size_t n = SIZE_MAX) const;
+ uint16_t get_text_width(FSTR_P str, size_t n = SIZE_MAX) const;
+};
+
+/******************* FT800/810 Graphic Commands *********************************/
+
+class CLCD::CommandFifo {
+ protected:
+ #if FTDI_API_LEVEL >= 810
+ uint32_t getRegCmdBSpace();
+ #else
+ static uint32_t command_write_ptr;
+ template bool _write_unaligned(T data, uint16_t len);
+ #endif
+ void start();
+
+ public:
+ template bool write(T data, uint16_t len);
+
+ public:
+ CommandFifo() {start();}
+
+ static void reset();
+ static bool is_processing();
+ static bool has_fault();
+
+ void execute();
+
+ void cmd(uint32_t cmd32);
+ void cmd(void *data, uint16_t len);
+
+ void dlstart() {cmd(FTDI::CMD_DLSTART);}
+ void swap() {cmd(FTDI::CMD_SWAP);}
+ void coldstart() {cmd(FTDI::CMD_COLDSTART);}
+ void screensaver() {cmd(FTDI::CMD_SCREENSAVER);}
+ void stop() {cmd(FTDI::CMD_STOP);}
+ void loadidentity() {cmd(FTDI::CMD_LOADIDENTITY);}
+ void setmatrix() {cmd(FTDI::CMD_SETMATRIX);}
+
+ void fgcolor (uint32_t rgb);
+ void bgcolor (uint32_t rgb);
+ void gradcolor (uint32_t rgb);
+
+ void track (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t tag);
+ void clock (int16_t x, int16_t y, int16_t r, uint16_t options, int16_t h, int16_t m, int16_t s, int16_t ms);
+ void gauge (int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t major, uint16_t minor, uint16_t val, uint16_t range);
+ void dial (int16_t x, int16_t y, int16_t r, uint16_t options, uint16_t val);
+ void slider (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t range);
+ void progress (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t range);
+ void scrollbar (int16_t x, int16_t y, int16_t w, int16_t h, uint16_t options, uint16_t val, uint16_t size, uint16_t range);
+ void number (int16_t x, int16_t y, int16_t font, uint16_t options, int32_t n);
+ void spinner (int16_t x, int16_t y, uint16_t style, uint16_t scale);
+ void sketch (int16_t x, int16_t y, uint16_t w, uint16_t h, uint32_t ptr, uint16_t format);
+ void gradient (int16_t x0, int16_t y0, uint32_t rgb0, int16_t x1, int16_t y1, uint32_t rgb1);
+ void snapshot (uint32_t ptr);
+ void loadimage (uint32_t ptr, uint32_t options);
+ void getprops (uint32_t ptr, uint32_t width, uint32_t height);
+
+ void scale (int32_t sx, int32_t sy);
+ void rotate (int32_t a);
+ void translate (int32_t tx, int32_t ty);
+
+ #if FTDI_API_LEVEL >= 810
+ void setbase (uint8_t base);
+ void setrotate (uint8_t rotation);
+ void setbitmap (uint32_t ptr, uint16_t fmt, uint16_t w, uint16_t h);
+ void snapshot2 (uint32_t fmt, uint32_t ptr, int16_t x, int16_t y, uint16_t w, uint16_t h);
+ void mediafifo (uint32_t ptr, uint32_t size);
+ void playvideo (uint32_t options);
+ void videostart();
+ void videoframe(uint32_t dst, uint32_t ptr);
+ void romfont (uint8_t font, uint8_t romslot);
+ #endif
+
+ // All the following must be followed by str()
+ void text (int16_t x, int16_t y, int16_t font, uint16_t options);
+ void button (int16_t x, int16_t y, int16_t w, int16_t h, int16_t font, uint16_t option);
+ void toggle (int16_t x, int16_t y, int16_t w, int16_t font, uint16_t options, bool state);
+ void keys (int16_t x, int16_t y, int16_t w, int16_t h, int16_t font, uint16_t options);
+
+ // Sends the string portion of text, button, toggle and keys.
+ void str (const char * data, size_t maxlen);
+ void str (const char * data);
+ void str (FSTR_P data);
+
+ void memzero (uint32_t ptr, uint32_t size);
+ void memset (uint32_t ptr, uint32_t value, uint32_t size);
+ void memcpy (uint32_t dst, uint32_t src, uint32_t size);
+ void memcrc (uint32_t ptr, uint32_t num, uint32_t result);
+ void memwrite (uint32_t ptr, uint32_t value);
+ void inflate (uint32_t ptr);
+ void getptr (uint32_t result);
+ void append (uint32_t ptr, uint32_t size);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h
new file mode 100644
index 0000000..20b1a3e
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h
@@ -0,0 +1,415 @@
+/***************
+ * constants.h *
+ ***************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+/****************************************************************************
+ * This header defines constants and commands for the FTDI FT810 LCD Driver *
+ * chip. *
+ ****************************************************************************/
+
+#pragma once
+
+// OPTIONS
+
+namespace FTDI {
+ constexpr uint16_t OPT_3D = 0x0000;
+ constexpr uint16_t OPT_RGB565 = 0x0000;
+ constexpr uint16_t OPT_MONO = 0x0001;
+ constexpr uint16_t OPT_NODL = 0x0002;
+ constexpr uint16_t OPT_FLAT = 0x0100;
+ constexpr uint16_t OPT_SIGNED = 0x0100;
+ constexpr uint16_t OPT_CENTERX = 0x0200;
+ constexpr uint16_t OPT_CENTERY = 0x0400;
+ constexpr uint16_t OPT_CENTER = (OPT_CENTERX | OPT_CENTERY);
+ constexpr uint16_t OPT_RIGHTX = 0x0800;
+ constexpr uint16_t OPT_NOBACK = 0x1000;
+ constexpr uint16_t OPT_NOTICKS = 0x2000;
+ constexpr uint16_t OPT_NOHM = 0x4000;
+ constexpr uint16_t OPT_NOPOINTER = 0x4000;
+ constexpr uint16_t OPT_NOSECS = 0x8000;
+ constexpr uint16_t OPT_NOHANDS = (OPT_NOPOINTER | OPT_NOSECS);
+}
+
+namespace FTDI_FT810 {
+ constexpr uint16_t OPT_NOTEAR = 0x0004;
+ constexpr uint16_t OPT_FULLSCREEN = 0x0008;
+ constexpr uint16_t OPT_MEDIAFIFO = 0x0010;
+ constexpr uint16_t OPT_SOUND = 0x0020;
+}
+
+// GPIO Bits
+
+namespace FTDI {
+ constexpr uint8_t GPIO_GP0 = 1 << 0;
+ constexpr uint8_t GPIO_GP1 = 1 << 1;
+ constexpr uint8_t GPIO_DISP = 1 << 7;
+}
+
+namespace FTDI_FT810 {
+ constexpr uint16_t GPIOX_GP0 = 1 << 0;
+ constexpr uint16_t GPIOX_GP1 = 1 << 1;
+ constexpr uint16_t GPIOX_DISP = 1 << 15;
+}
+
+// HOST COMMANDS
+
+namespace FTDI {
+ constexpr uint8_t ACTIVE = 0x00;
+ constexpr uint8_t STANDBY = 0x41;
+ constexpr uint8_t SLEEP = 0x42;
+ constexpr uint8_t PWRDOWN = 0x50;
+ constexpr uint8_t CLKEXT = 0x44;
+ constexpr uint8_t CLKINT = 0x48;
+ constexpr uint8_t CORESET = 0x68;
+}
+
+namespace FTDI_FT800 {
+ constexpr uint8_t CLK48M = 0x62;
+ constexpr uint8_t CLK36M = 0x61;
+}
+
+namespace FTDI_FT810 {
+ constexpr uint8_t CLKSEL = 0x61;
+}
+
+// DISPLAY LIST COMMANDS
+
+namespace FTDI {
+ constexpr uint8_t ARGB1555 = 0;
+ constexpr uint8_t L1 = 1;
+ constexpr uint8_t L2 = 17;
+ constexpr uint8_t L4 = 2;
+ constexpr uint8_t L8 = 3;
+ constexpr uint8_t RGB332 = 4;
+ constexpr uint8_t ARGB2 = 5;
+ constexpr uint8_t ARGB4 = 6;
+ constexpr uint8_t RGB565 = 7;
+ constexpr uint8_t PALETTED = 8;
+ constexpr uint8_t TEXT8X8 = 9;
+ constexpr uint8_t TEXTVGA = 10;
+ constexpr uint8_t BARGRAPH = 11;
+
+ constexpr uint8_t ALPHA_FUNC_NEVER = 0;
+ constexpr uint8_t ALPHA_FUNC_LESS = 1;
+ constexpr uint8_t ALPHA_FUNC_LEQUAL = 2;
+ constexpr uint8_t ALPHA_FUNC_GREATER = 3;
+ constexpr uint8_t ALPHA_FUNC_GEQUAL = 4;
+ constexpr uint8_t ALPHA_FUNC_EQUAL = 5;
+ constexpr uint8_t ALPHA_FUNC_NOTEQUAL = 6;
+ constexpr uint8_t ALPHA_FUNC_ALWAYS = 7;
+
+ constexpr uint8_t NEAREST = 0;
+ constexpr uint8_t BILINEAR = 1;
+ constexpr uint8_t BORDER = 0;
+ constexpr uint8_t REPEAT = 1;
+
+ constexpr uint8_t BLEND_FUNC_ZERO = 0;
+ constexpr uint8_t BLEND_FUNC_ONE = 1;
+ constexpr uint8_t BLEND_FUNC_SRC_ALPHA = 2;
+ constexpr uint8_t BLEND_FUNC_DST_ALPHA = 3;
+ constexpr uint8_t BLEND_FUNC_ONE_MINUS_SRC_ALPHA = 4;
+ constexpr uint8_t BLEND_FUNC_ONE_MINUS_DST_ALPHA = 5;
+
+ constexpr uint32_t COLOR_MASK_RED = 8;
+ constexpr uint32_t COLOR_MASK_GRN = 4;
+ constexpr uint32_t COLOR_MASK_BLU = 2;
+ constexpr uint32_t COLOR_MASK_ALPHA = 1;
+
+ constexpr uint8_t STENCIL_FUNC_NEVER = 0;
+ constexpr uint8_t STENCIL_FUNC_LESS = 1;
+ constexpr uint8_t STENCIL_FUNC_LEQUAL = 2;
+ constexpr uint8_t STENCIL_FUNC_GREATER = 3;
+ constexpr uint8_t STENCIL_FUNC_GEQUAL = 4;
+ constexpr uint8_t STENCIL_FUNC_EQUAL = 5;
+ constexpr uint8_t STENCIL_FUNC_NOTEQUAL = 6;
+ constexpr uint8_t STENCIL_FUNC_ALWAYS = 7;
+
+ constexpr uint8_t STENCIL_OP_ZERO = 0;
+ constexpr uint8_t STENCIL_OP_KEEP = 1;
+ constexpr uint8_t STENCIL_OP_REPLACE = 2;
+ constexpr uint8_t STENCIL_OP_INCR = 3;
+ constexpr uint8_t STENCIL_OP_DECR = 4;
+ constexpr uint8_t STENCIL_OP_INVERT = 5;
+
+ typedef enum : uint32_t {
+ BITMAPS = 1,
+ POINTS = 2,
+ LINES = 3,
+ LINE_STRIP = 4,
+ EDGE_STRIP_R = 5,
+ EDGE_STRIP_L = 6,
+ EDGE_STRIP_A = 7,
+ EDGE_STRIP_B = 8,
+ RECTS = 9
+ } begin_t;
+}
+
+namespace FTDI_FT800_DL {
+ constexpr uint32_t ALPHA_FUNC = 0x09000000;
+ constexpr uint32_t BEGIN = 0x1F000000;
+ constexpr uint32_t BITMAP_HANDLE = 0x05000000;
+ constexpr uint32_t BITMAP_LAYOUT = 0x07000000;
+ constexpr uint32_t BITMAP_SIZE = 0x08000000;
+ constexpr uint32_t BITMAP_SOURCE = 0x01000000;
+ constexpr uint32_t BITMAP_TRANSFORM_A = 0x15000000;
+ constexpr uint32_t BITMAP_TRANSFORM_B = 0x16000000;
+ constexpr uint32_t BITMAP_TRANSFORM_C = 0x17000000;
+ constexpr uint32_t BITMAP_TRANSFORM_D = 0x18000000;
+ constexpr uint32_t BITMAP_TRANSFORM_E = 0x19000000;
+ constexpr uint32_t BITMAP_TRANSFORM_F = 0x1A000000;
+ constexpr uint32_t BLEND_FUNC = 0x0B000000;
+ constexpr uint32_t CALL = 0x1D000000;
+ constexpr uint32_t CELL = 0x06000000;
+ constexpr uint32_t CLEAR = 0x26000000;
+ constexpr uint32_t CLEAR_COLOR_BUFFER = 0x00000004;
+ constexpr uint32_t CLEAR_STENCIL_BUFFER = 0x00000002;
+ constexpr uint32_t CLEAR_TAG_BUFFER = 0x00000001;
+ constexpr uint32_t CLEAR_COLOR_A = 0x0F000000;
+ constexpr uint32_t CLEAR_COLOR_RGB = 0x02000000;
+ constexpr uint32_t CLEAR_STENCIL = 0x11000000;
+ constexpr uint32_t CLEAR_TAG = 0x12000000;
+ constexpr uint32_t COLOR_A = 0x10000000;
+ constexpr uint32_t COLOR_MASK = 0x20000000;
+ constexpr uint32_t COLOR_RGB = 0x04000000;
+ constexpr uint32_t DL_DISPLAY = 0x00000000;
+ constexpr uint32_t END = 0x21000000;
+ constexpr uint32_t JUMP = 0x1E000000;
+ constexpr uint32_t LINE_WIDTH = 0x0E000000;
+ constexpr uint32_t MACRO = 0x25000000;
+ constexpr uint32_t POINT_SIZE = 0x0D000000;
+ constexpr uint32_t RESTORE_CONTEXT = 0x23000000;
+ constexpr uint32_t RETURN = 0x24000000;
+ constexpr uint32_t SAVE_CONTEXT = 0x22000000;
+ constexpr uint32_t SCISSOR_SIZE = 0x1C000000;
+ constexpr uint32_t SCISSOR_XY = 0x1B000000;
+ constexpr uint32_t STENCIL_FUNC = 0x0A000000;
+ constexpr uint32_t STENCIL_MASK = 0x13000000;
+ constexpr uint32_t STENCIL_OP = 0x0C000000;
+ constexpr uint32_t TAG = 0x03000000;
+ constexpr uint32_t TAG_MASK = 0x14000000;
+ constexpr uint32_t VERTEX2F = 0x40000000;
+ constexpr uint32_t VERTEX2II = 0x80000000;
+}
+
+namespace FTDI_FT810_DL {
+ constexpr uint32_t NOP = 0x25000000;
+ constexpr uint32_t BITMAP_LAYOUT_H = 0x28000000;
+ constexpr uint32_t BITMAP_SIZE_H = 0x29000000;
+ constexpr uint32_t VERTEX_FORMAT = 0x27000000;
+ constexpr uint32_t VERTEX_TRANSLATE_X = 0x2B000000;
+ constexpr uint32_t VERTEX_TRANSLATE_Y = 0x2C000000;
+}
+
+// CO-PROCESSOR ENGINE COMMANDS
+namespace FTDI {
+ constexpr uint32_t CMD_DLSTART = 0xFFFFFF00;
+ constexpr uint32_t CMD_SWAP = 0xFFFFFF01;
+ constexpr uint32_t CMD_COLDSTART = 0xFFFFFF32;
+ constexpr uint32_t CMD_INTERRUPT = 0xFFFFFF02;
+ constexpr uint32_t CMD_APPEND = 0xFFFFFF1E;
+ constexpr uint32_t CMD_REGREAD = 0xFFFFFF19;
+ constexpr uint32_t CMD_MEMWRITE = 0xFFFFFF1A;
+ constexpr uint32_t CMD_INFLATE = 0xFFFFFF22;
+ constexpr uint32_t CMD_LOADIMAGE = 0xFFFFFF24;
+ constexpr uint32_t CMD_MEMCRC = 0xFFFFFF18;
+ constexpr uint32_t CMD_MEMZERO = 0xFFFFFF1C;
+ constexpr uint32_t CMD_MEMSET = 0xFFFFFF1B;
+ constexpr uint32_t CMD_MEMCPY = 0xFFFFFF1D;
+ constexpr uint32_t CMD_BUTTON = 0xFFFFFF0D;
+ constexpr uint32_t CMD_CLOCK = 0xFFFFFF14;
+ constexpr uint32_t CMD_FGCOLOR = 0xFFFFFF0A;
+ constexpr uint32_t CMD_BGCOLOR = 0xFFFFFF09;
+ constexpr uint32_t CMD_GRADCOLOR = 0xFFFFFF34;
+ constexpr uint32_t CMD_GAUGE = 0xFFFFFF13;
+ constexpr uint32_t CMD_GRADIENT = 0xFFFFFF0B;
+ constexpr uint32_t CMD_KEYS = 0xFFFFFF0E;
+ constexpr uint32_t CMD_PROGRESS = 0xFFFFFF0F;
+ constexpr uint32_t CMD_SCROLLBAR = 0xFFFFFF11;
+ constexpr uint32_t CMD_SLIDER = 0xFFFFFF10;
+ constexpr uint32_t CMD_DIAL = 0xFFFFFF2D;
+ constexpr uint32_t CMD_TOGGLE = 0xFFFFFF12;
+ constexpr uint32_t CMD_TEXT = 0xFFFFFF0C;
+ constexpr uint32_t CMD_NUMBER = 0xFFFFFF2E;
+ constexpr uint32_t CMD_LOADIDENTITY = 0xFFFFFF26;
+ constexpr uint32_t CMD_SETMATRIX = 0xFFFFFF2A;
+ constexpr uint32_t CMD_GETMATRIX = 0xFFFFFF33;
+ constexpr uint32_t CMD_GETPTR = 0xFFFFFF23;
+ constexpr uint32_t CMD_GETPROPS = 0xFFFFFF25;
+ constexpr uint32_t CMD_SCALE = 0xFFFFFF28;
+ constexpr uint32_t CMD_ROTATE = 0xFFFFFF29;
+ constexpr uint32_t CMD_TRANSLATE = 0xFFFFFF27;
+ constexpr uint32_t CMD_CALIBRATE = 0xFFFFFF15;
+ constexpr uint32_t CMD_SPINNER = 0xFFFFFF16;
+ constexpr uint32_t CMD_SCREENSAVER = 0xFFFFFF2F;
+ constexpr uint32_t CMD_SKETCH = 0xFFFFFF30;
+ constexpr uint32_t CMD_STOP = 0xFFFFFF17;
+ constexpr uint32_t CMD_SETFONT = 0xFFFFFF2B;
+ constexpr uint32_t CMD_TRACK = 0xFFFFFF2C;
+ constexpr uint32_t CMD_SNAPSHOT = 0xFFFFFF1F;
+ constexpr uint32_t CMD_LOGO = 0xFFFFFF31;
+}
+
+namespace FTDI_FT810 {
+ constexpr uint32_t CMD_SETROTATE = 0xFFFFFF36;
+ constexpr uint32_t CMD_SNAPSHOT2 = 0xFFFFFF37;
+ constexpr uint32_t CMD_SETBASE = 0xFFFFFF38;
+ constexpr uint32_t CMD_MEDIAFIFO = 0xFFFFFF39;
+ constexpr uint32_t CMD_PLAYVIDEO = 0xFFFFFF3A;
+ constexpr uint32_t CMD_SETFONT2 = 0xFFFFFF3B;
+ constexpr uint32_t CMD_SETSCRATCH = 0xFFFFFF3C;
+ constexpr uint32_t CMD_ROMFONT = 0xFFFFFF3F;
+ constexpr uint32_t CMD_VIDEOSTART = 0xFFFFFF40;
+ constexpr uint32_t CMD_VIDEOFRAME = 0xFFFFFF41;
+ constexpr uint32_t CMD_SETBITMAP = 0xFFFFFF43;
+}
+
+namespace FTDI {
+ enum effect_t : unsigned char {
+ SILENCE = 0x00,
+ SQUARE_WAVE = 0x01,
+ SINE_WAVE = 0x02,
+ SAWTOOTH_WAVE = 0x03,
+ TRIANGLE_WAVE = 0x04,
+ BEEPING = 0x05,
+ ALARM = 0x06,
+ WARBLE = 0x07,
+ CAROUSEL = 0x08,
+ SHORT_PIPS_1 = 0x10,
+ SHORT_PIPS_2 = 0x11,
+ SHORT_PIPS_3 = 0x12,
+ SHORT_PIPS_4 = 0x13,
+ SHORT_PIPS_5 = 0x14,
+ SHORT_PIPS_6 = 0x15,
+ SHORT_PIPS_7 = 0x16,
+ SHORT_PIPS_8 = 0x17,
+ SHORT_PIPS_9 = 0x18,
+ SHORT_PIPS_10 = 0x19,
+ SHORT_PIPS_11 = 0x1A,
+ SHORT_PIPS_12 = 0x1B,
+ SHORT_PIPS_13 = 0x1C,
+ SHORT_PIPS_14 = 0x1D,
+ SHORT_PIPS_15 = 0x1E,
+ SHORT_PIPS_16 = 0x1F,
+ DTMF_POUND = 0x23,
+ DTMF_STAR = 0x2C,
+ DTMF_0 = 0x30,
+ DTMF_1 = 0x31,
+ DTMF_2 = 0x32,
+ DTMF_3 = 0x33,
+ DTMF_4 = 0x34,
+ DTMF_5 = 0x35,
+ DTMF_6 = 0x36,
+ DTMF_7 = 0x37,
+ DTMF_8 = 0x38,
+ DTMF_9 = 0x39,
+ HARP = 0x40,
+ XYLOPHONE = 0x41,
+ TUBA = 0x42,
+ GLOCKENSPIEL = 0x43,
+ ORGAN = 0x44,
+ TRUMPET = 0x45,
+ PIANO = 0x46,
+ CHIMES = 0x47,
+ MUSIC_BOX = 0x48,
+ BELL = 0x49,
+ CLICK = 0x50,
+ SWITCH = 0x51,
+ COWBELL = 0x52,
+ NOTCH = 0x53,
+ HIHAT = 0x54,
+ KICKDRUM = 0x55,
+ POP = 0x56,
+ CLACK = 0x57,
+ CHACK = 0x58,
+ MUTE = 0x60,
+ UNMUTE = 0x61
+ };
+
+ enum note_t : unsigned char {
+ END_SONG = 0xFF,
+ REST = 0x00,
+
+ NOTE_C1 = 0x18, // 24
+ NOTE_C1S = 0x19,
+ NOTE_D1 = 0x1A,
+ NOTE_D1S = 0x1B,
+ NOTE_E1 = 0x1C,
+ NOTE_F1 = 0x1D,
+ NOTE_F1S = 0x1E,
+ NOTE_G1 = 0x1F,
+ NOTE_G1S = 0x20,
+ NOTE_A1 = 0x21,
+ NOTE_A1S = 0x22,
+ NOTE_B1 = 0x23,
+
+ NOTE_C2 = 0x24, //36
+ NOTE_C2S = 0x25,
+ NOTE_D2 = 0x26,
+ NOTE_D2S = 0x27,
+ NOTE_E2 = 0x28,
+ NOTE_F2 = 0x29,
+ NOTE_F2S = 0x2A,
+ NOTE_G2 = 0x2B,
+ NOTE_G2S = 0x2C,
+ NOTE_A2 = 0x2D,
+ NOTE_A2S = 0x2E,
+ NOTE_B2 = 0x2F,
+
+ NOTE_C3 = 0x30,
+ NOTE_C3S = 0x31,
+ NOTE_D3 = 0x32,
+ NOTE_D3S = 0x33,
+ NOTE_E3 = 0x34,
+ NOTE_F3 = 0x35,
+ NOTE_F3S = 0x36,
+ NOTE_G3 = 0x37,
+ NOTE_G3S = 0x38,
+ NOTE_A3 = 0x39,
+ NOTE_A3S = 0x3A,
+ NOTE_B3 = 0x3B,
+
+ NOTE_C4 = 0x3C,
+ NOTE_C4S = 0x3D,
+ NOTE_D4 = 0x3E,
+ NOTE_D4S = 0x3F,
+ NOTE_E4 = 0x40,
+ NOTE_F4 = 0x41,
+ NOTE_F4S = 0x42,
+ NOTE_G4 = 0x43,
+ NOTE_G4S = 0x44,
+ NOTE_A4 = 0x45,
+ NOTE_A4S = 0x46,
+ NOTE_B4 = 0x47,
+
+ NOTE_C5 = 0x48,
+ NOTE_C5S = 0x49,
+ NOTE_D5 = 0x4A,
+ NOTE_D5S = 0x4B,
+ NOTE_E5 = 0x4C,
+ NOTE_F5 = 0x4D,
+ NOTE_F5S = 0x4E,
+ NOTE_G5 = 0x4F,
+ NOTE_G5S = 0x50,
+ NOTE_A5 = 0x51,
+ NOTE_A5S = 0x52,
+ NOTE_B5 = 0x53,
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/display_list.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/display_list.h
new file mode 100644
index 0000000..d6afe78
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/display_list.h
@@ -0,0 +1,118 @@
+/******************
+ * display_list.h *
+ *****************/
+
+/**********************************************************************************
+ * Adapted from: *
+ * https://github.com/RudolphRiedel/FT800-FT813 *
+ * By Rudolph Riedel *
+ * *
+ * MIT License *
+ * *
+ * Copyright (c) 2017 *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy *
+ * of this software and associated documentation files (the "Software"), to deal *
+ * in the Software without restriction, including without limitation the rights *
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
+ * copies of the Software, and to permit persons to whom the Software is *
+ * furnished to do so, subject to the following conditions: *
+ * *
+ * The above copyright notice and this permission notice shall be included in all *
+ * copies or substantial portions of the Software. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE *
+ * SOFTWARE. *
+ * *
+ **********************************************************************************/
+
+#pragma once
+
+namespace FTDI {
+ /* FT8xx graphics engine specific macros useful for static display list generation */
+ inline uint32_t ALPHA_FUNC(uint8_t func, uint8_t ref) {return DL::ALPHA_FUNC|((func&7UL)<<8)|(ref&255UL);}
+ inline uint32_t BEGIN(begin_t prim) {return DL::BEGIN|(prim&15UL);}
+
+ inline uint32_t BITMAP_SOURCE(uint32_t ram_g_addr) {return DL::BITMAP_SOURCE|(ram_g_addr);}
+ inline uint32_t BITMAP_HANDLE(uint8_t handle) {return DL::BITMAP_HANDLE|(handle&31UL);}
+ inline uint32_t BITMAP_LAYOUT(uint8_t format, uint16_t linestride, uint16_t height)
+ {return DL::BITMAP_LAYOUT|((format&31UL)<<19)|((linestride&1023UL)<<9)|(height&511UL);}
+
+ inline uint32_t BITMAP_SIZE(uint8_t filter, uint8_t wrapx, uint8_t wrapy, uint16_t width, uint16_t height)
+ {return DL::BITMAP_SIZE|((filter&1UL)<<20)|((wrapx&1UL)<<19)|((wrapy&1UL)<<18)|((width&511UL)<<9)|(height&511UL);}
+ #if FTDI_API_LEVEL >= 810
+ inline uint32_t BITMAP_LAYOUT_H(uint8_t linestride, uint8_t height)
+ {return DL::BITMAP_LAYOUT_H|((linestride&3UL)<<2)|(height&3UL);}
+ inline uint32_t BITMAP_SIZE_H(uint8_t width, uint8_t height)
+ {return DL::BITMAP_SIZE_H|((width&3UL)<<2)|(height&3UL);}
+ #endif
+ inline uint32_t BITMAP_TRANSFORM_A(uint16_t a) {return DL::BITMAP_TRANSFORM_A|(a&131071UL);}
+ inline uint32_t BITMAP_TRANSFORM_B(uint16_t b) {return DL::BITMAP_TRANSFORM_B|(b&131071UL);}
+ inline uint32_t BITMAP_TRANSFORM_C(uint32_t c) {return DL::BITMAP_TRANSFORM_C|(c&16777215UL);}
+ inline uint32_t BITMAP_TRANSFORM_D(uint16_t d) {return DL::BITMAP_TRANSFORM_D|(d&131071UL);}
+ inline uint32_t BITMAP_TRANSFORM_E(uint16_t e) {return DL::BITMAP_TRANSFORM_E|(e&131071UL);}
+ inline uint32_t BITMAP_TRANSFORM_F(uint32_t f) {return DL::BITMAP_TRANSFORM_F|(f&16777215UL);}
+ inline uint32_t BLEND_FUNC(uint8_t src,uint8_t dst) {return DL::BLEND_FUNC|((src&7UL)<<3)|(dst&7UL);}
+ inline uint32_t CALL(uint16_t dest) {return DL::CALL|(dest&65535UL);}
+ inline uint32_t CELL(uint8_t cell) {return DL::CELL|(cell&127UL);}
+ inline uint32_t CLEAR(bool c,bool s,bool t) {return DL::CLEAR|((c?1UL:0UL)<<2)|((s?1UL:0UL)<<1)|(t?1UL:0UL);}
+ inline uint32_t CLEAR_COLOR_A(uint8_t alpha) {return DL::CLEAR_COLOR_A|(alpha&255UL);}
+ inline uint32_t CLEAR_COLOR_RGB(uint8_t red, uint8_t green, uint8_t blue)
+ {return DL::CLEAR_COLOR_RGB|((red&255UL)<<16)|((green&255UL)<<8)|(blue&255UL);}
+ inline uint32_t CLEAR_COLOR_RGB(uint32_t rgb) {return DL::CLEAR_COLOR_RGB|(rgb&0xFFFFFF);}
+ inline uint32_t CLEAR_STENCIL(uint8_t s) {return DL::CLEAR_STENCIL|(s&255UL);}
+ inline uint32_t CLEAR_TAG(uint8_t s) {return DL::CLEAR_TAG|(s&255UL);}
+ inline uint32_t COLOR_A(uint8_t alpha) {return DL::COLOR_A|(alpha&255UL);}
+ inline uint32_t COLOR_MASK(bool r, bool g, bool b, bool a) {return DL::COLOR_MASK|((r?1UL:0UL)<<3)|((g?1UL:0UL)<<2)|((b?1UL:0UL)<<1)|(a?1UL:0UL);}
+ inline uint32_t COLOR_RGB(uint8_t red,uint8_t green,uint8_t blue)
+ {return DL::COLOR_RGB|((red&255UL)<<16)|((green&255UL)<<8)|(blue&255UL);}
+ inline uint32_t COLOR_RGB(uint32_t rgb) {return DL::COLOR_RGB|(rgb&0xFFFFFF);}
+ /* inline uint32_t DISPLAY() {return (0UL<<24)) */
+ inline uint32_t END() {return DL::END;}
+ inline uint32_t JUMP(uint16_t dest) {return DL::JUMP|(dest&65535UL);}
+ inline uint32_t LINE_WIDTH(uint16_t width) {return DL::LINE_WIDTH|(width&4095UL);}
+ inline uint32_t MACRO(uint8_t m) {return DL::MACRO|(m&1UL);}
+ inline uint32_t POINT_SIZE(uint16_t size) {return DL::POINT_SIZE|(size&8191UL);}
+ inline uint32_t RESTORE_CONTEXT() {return DL::RESTORE_CONTEXT;}
+ inline uint32_t RETURN () {return DL::RETURN;}
+ inline uint32_t SAVE_CONTEXT() {return DL::SAVE_CONTEXT;}
+ inline uint32_t SCISSOR_XY(uint16_t x,uint16_t y) {
+ return DL::SCISSOR_XY |
+ (FTDI::ftdi_chip >= 810
+ ? ((x&2047UL)<<11)|(y&2047UL)
+ : ((x& 511UL)<<10)|(y&511UL));
+ }
+ inline uint32_t SCISSOR_SIZE(uint16_t w,uint16_t h) {
+ return DL::SCISSOR_SIZE |
+ (FTDI::ftdi_chip >= 810
+ ? ((w&4095UL)<<12)|(h&4095UL)
+ : ((w&1023UL)<<10)|(h&1023UL));
+ }
+ inline uint32_t SCISSOR_XY() {return DL::SCISSOR_XY;}
+ inline uint32_t SCISSOR_SIZE() {
+ return DL::SCISSOR_SIZE |
+ (FTDI::ftdi_chip >= 810
+ ? (2048UL<<12)|(2048UL)
+ : ( 512UL<<10)|( 512UL));
+ }
+ inline uint32_t STENCIL_FUNC(uint16_t func, uint8_t ref, uint8_t mask)
+ {return DL::STENCIL_FUNC|((func&7UL)<<16)|((ref&255UL)<<8)|(mask&255UL);}
+ inline uint32_t STENCIL_MASK(uint8_t mask) {return DL::STENCIL_MASK|(mask&255UL);}
+ inline uint32_t STENCIL_OP(uint8_t sfail, uint8_t spass) {return DL::STENCIL_OP|(((sfail)&7UL)<<3)|(spass&7UL);}
+ inline uint32_t TAG(uint8_t s) {return DL::TAG|(s&255UL);}
+ inline uint32_t TAG_MASK(bool mask) {return DL::TAG_MASK|(mask?1:0);}
+ inline uint32_t VERTEX2F(uint16_t x, uint16_t y) {return DL::VERTEX2F|((x&32767UL)<<15)|(y&32767UL);}
+ inline uint32_t VERTEX2II(uint16_t x,uint16_t y, uint8_t handle = 0, uint8_t cell = 0)
+ {return DL::VERTEX2II|((x&511UL)<<21)|((y&511UL)<<12)|((handle&31UL)<<7)|(cell&127UL);}
+
+ #if FTDI_API_LEVEL >= 810
+ inline uint32_t VERTEX_FORMAT(uint8_t frac) {return DL::VERTEX_FORMAT|(frac&7UL);}
+ inline uint32_t VERTEX_TRANSLATE_X(int32_t x) {return DL::VERTEX_TRANSLATE_X|(x&131071UL);}
+ inline uint32_t VERTEX_TRANSLATE_Y(int32_t y) {return DL::VERTEX_TRANSLATE_Y|(y&131071UL);}
+ #endif
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/ftdi_basic.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/ftdi_basic.h
new file mode 100644
index 0000000..47cd698
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/ftdi_basic.h
@@ -0,0 +1,40 @@
+/****************
+ * ftdi_basic.h *
+ ****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2019 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#include "../compat.h"
+
+#ifndef __MARLIN_FIRMWARE__
+ #define FTDI_BASIC
+#endif
+
+#ifdef FTDI_BASIC
+ #include "registers_ft800.h"
+ #include "registers_ft810.h"
+ #include "constants.h"
+ #include "boards.h"
+ #include "commands.h"
+ #include "spi.h"
+ #include "display_list.h"
+ #include "resolutions.h"
+#endif
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft800.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft800.h
new file mode 100644
index 0000000..2605370
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft800.h
@@ -0,0 +1,150 @@
+/*********************
+ * registers_ft800.h *
+ *********************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+/****************************************************************************
+ * This header defines registers for the FTDI FT800 LCD Driver chip. *
+ ****************************************************************************/
+
+/*******************************************************************************
+ * FT810 *
+ * *
+ * START END ADDR SIZE NAME DESCRIPTION *
+ * *
+ * 0x000000 0x03FFFF 256 kB RAM_G Main Graphics RAM *
+ * *
+ * 0x0C0000 0x0C0003 4 B ROM_CHIPID [0:1] 0x800 Chip Id *
+ * [1:2] 0x0100 Vers ID *
+ * *
+ * 0x0BB23C 0x0FFFFB 275 kB ROM_FONT Font table and bitmap *
+ * *
+ * 0x0FFFFC 0x0FFFFF 4 B ROM_FONT_ADDR Font table pointer address *
+ * *
+ * 0x100000 0x101FFF 8 kB RAM_DL Display List RAM *
+ * *
+ * 0x102000 0x1023FF 1 kB RAM_PAL Palette RAM *
+ * *
+ * 0x102400 0x10257F 380 B * Registers *
+ * *
+ * 0x108000 0x108FFF 4 kB RAM_CMD Command Buffer *
+ * *
+ *******************************************************************************/
+
+#pragma once
+
+namespace FTDI {
+ struct ft800_memory_map {
+
+ // MEMORY LOCATIONS FT800
+ static constexpr uint32_t RAM_G = 0x000000; // Main Graphics RAM
+ static constexpr uint32_t ROM_CHIPID = 0x0C0000; // Chip ID/Version ID
+ static constexpr uint32_t ROM_FONT = 0x0BB23C; // Font ROM
+ static constexpr uint32_t ROM_FONT_ADDR = 0x0FFFFC; // Font Table Pointer
+ static constexpr uint32_t RAM_DL = 0x100000; // Display List RAM
+ static constexpr uint32_t RAM_PAL = 0x102000; // Palette RAM
+ static constexpr uint32_t RAM_REG = 0x102400; // Registers
+ static constexpr uint32_t RAM_CMD = 0x108000; // Command Buffer
+
+ static constexpr uint32_t RAM_G_SIZE = 256*1024L; // 256k
+ };
+
+ struct ft800_registers {
+ // REGISTERS AND ADDRESSES FT800
+
+ // REGISTER ADDRESS SIZE RESET VALUE TYPE DESCRIPTION
+
+ static constexpr uint32_t ID = 0x102400; // 8 0x7C r Identification Register, Always 0x7C
+ static constexpr uint32_t FRAMES = 0x102404; // 32 0x00000000 r Frame Counter, Since Reset
+ static constexpr uint32_t CLOCK = 0x102408; // 32 0x00000000 r Clock cycles, Since Reset
+ static constexpr uint32_t FREQUENCY = 0x10240C; // 28 0x03938700 r/w Main Clock Frequency
+ static constexpr uint32_t RENDERMODE = 0x102410; // 1 0x00 r/w Rendering Mode: 0 = normal, 1 = single-line
+ static constexpr uint32_t SNAPY = 0x102414; // 11 0x0000 r/w Scan Line Select for RENDERMODE 1
+ static constexpr uint32_t SNAPSHOT = 0x102418; // 1 - r Trigger for RENDERMODE 1
+ static constexpr uint32_t CPURESET = 0x10241C; // 3 0x02 r/w RESET Bit2 Audio - Bit1 Touch - Bit0 Graphics
+ static constexpr uint32_t TAP_CRC = 0x102420; // 32 - r Live Video Tap
+ static constexpr uint32_t TAP_MASK = 0x102424; // 32 0xFFFFFFFF r/w Live Video Tap Mask
+ static constexpr uint32_t HCYCLE = 0x102428; // 12 0x224 r/w Horizontal Total Cycle Count
+ static constexpr uint32_t HOFFSET = 0x10242C; // 12 0x02B r/w Horizontal Display Start Offset
+ static constexpr uint32_t HSIZE = 0x102430; // 12 0x1E0 r/w Horizontal Display Pixel Count
+ static constexpr uint32_t HSYNC0 = 0x102434; // 12 0x000 r/w Horizontal Sync Fall Offset
+ static constexpr uint32_t HSYNC1 = 0x102438; // 12 0x029 r/w Horizontal Sync Rise Offset
+ static constexpr uint32_t VCYCLE = 0x10243C; // 12 0x124 r/w Vertical Total Cycle Count
+ static constexpr uint32_t VOFFSET = 0x102440; // 12 0x00C r/w Vertical Display Start Offset
+ static constexpr uint32_t VSIZE = 0x102444; // 12 0x110 r/w Vertical Display Line Count
+ static constexpr uint32_t VSYNC0 = 0x102448; // 10 0x000 r/w Vertical Sync Fall Offset
+ static constexpr uint32_t VSYNC1 = 0x10244C; // 10 0x00A r/w Vertical Sync Rise Offset
+ static constexpr uint32_t DLSWAP = 0x102450; // 2 0x00 r/w Display List Swap Control
+ static constexpr uint32_t ROTATE = 0x102454; // 3 0x00 r/w Screen 90,180, 270 degree rotate
+ static constexpr uint32_t OUTBITS = 0x102458; // 9 0x1B6 r/w Output Resolution, 3x3x3 Bits
+ static constexpr uint32_t DITHER = 0x10245C; // 1 0x01 r/w Output Dither Enable
+ static constexpr uint32_t SWIZZLE = 0x102460; // 4 0x00 r/w Output RGB Swizzle, Pin Change for PCB Routing
+ static constexpr uint32_t CSPREAD = 0x102464; // 1 0x01 r/w Output Clock Spreading Enable
+ static constexpr uint32_t PCLK_POL = 0x102468; // 1 0x00 r/w PCLK Polarity: 0 = Rising Edge, 1 = Falling Edge
+ static constexpr uint32_t PCLK = 0x10246C; // 8 0x00 r/w PCLK Frequency Divider, 0 = Disable Clock
+ static constexpr uint32_t TAG_X = 0x102470; // 11 0x000 r/w Tag Query X Coordinate
+ static constexpr uint32_t TAG_Y = 0x102474; // 11 0x000 r/w Tag Query Y Coordinate
+ static constexpr uint32_t TAG = 0x102478; // 8 0x00 r Tag Query Result
+ static constexpr uint32_t VOL_PB = 0x10247C; // 8 0xFF r/w Audio Playback Volume
+ static constexpr uint32_t VOL_SOUND = 0x102480; // 8 0xFF r/w Audio Synthesizer Volume
+ static constexpr uint32_t SOUND = 0x102484; // 16 0x0000 r/w Audio Sound Effect Select
+ static constexpr uint32_t PLAY = 0x102488; // 1 0x00 r/w Audio Start Effect Playback
+ static constexpr uint32_t GPIO_DIR = 0x10248C; // 8 0x80 r/w GPIO Pin Direction: 0 = Input , 1 = Output
+ static constexpr uint32_t GPIO = 0x102490; // 8 0x00 r/w GPIO Pin Values for 0, 1, 7 Drive Strength 2, 3, 4, 5, 6
+ static constexpr uint32_t INT_FLAGS = 0x102498; // 8 0x00 r Interrupt Flags, Clear by Reading
+ static constexpr uint32_t INT_EN = 0x10249C; // 1 0x00 r/w Global Interrupt Enable
+ static constexpr uint32_t INT_MASK = 0x1024A0; // 8 0xFF r/w Interrupt Enable Mask
+ static constexpr uint32_t PLAYBACK_START = 0x1024A4; // 20 0x00000 r/w Audio Playback RAM Start Address
+ static constexpr uint32_t PLAYBACK_LENGTH = 0x1024A8; // 20 0x00000 r/w Audio Playback Sample Length (Bytes)
+ static constexpr uint32_t PLAYBACK_READPTR = 0x1024AC; // 20 - r Audio Playback Read Pointer
+ static constexpr uint32_t PLAYBACK_FREQ = 0x1024B0; // 16 0x1F40 r/w Audio Playback Frequency (Hz)
+ static constexpr uint32_t PLAYBACK_FORMAT = 0x1024B4; // 2 0x00 r/w Audio Playback Format
+ static constexpr uint32_t PLAYBACK_LOOP = 0x1024B8; // 1 0x00 r/w Audio Playback Loop Enable
+ static constexpr uint32_t PLAYBACK_PLAY = 0x1024BC; // 1 0x00 r Audio Start Playback
+ static constexpr uint32_t PWM_HZ = 0x1024C0; // 14 0x00FA r/w Backlight PWM Frequency (Hz)
+ static constexpr uint32_t PWM_DUTY = 0x1024C4; // 8 0x80 r/w Backlight PWM Duty Cycle: 0 = 0%, 128 = 100%
+ static constexpr uint32_t MACRO_0 = 0x1024C8; // 32 0x00000000 r/w Display List Macro Command 0
+ static constexpr uint32_t MACRO_1 = 0x1024CC; // 32 0x00000000 r/w Display List Macro Command 1
+ static constexpr uint32_t CMD_READ = 0x1024E4; // 12 0x000 r/w Command Buffer Read Pointer
+ static constexpr uint32_t CMD_WRITE = 0x1024E8; // 12 0x000 r/w Command Buffer Write Pointer
+ static constexpr uint32_t CMD_DL = 0x1024EC; // 13 0x0000 r/w Command Display List Offset
+ static constexpr uint32_t TOUCH_MODE = 0x1024F0; // 2 0x03 r/w Touch-Screen Sampling Mode
+ static constexpr uint32_t TOUCH_ADC_MODE = 0x1024F4; // 1 0x01 r/w Select Single Ended or Differential Sampling
+ static constexpr uint32_t TOUCH_CHARGE = 0x1024F8; // 16 0x1770 r/w Touch Screen Charge Time, n x 6 Clocks
+ static constexpr uint32_t TOUCH_SETTLE = 0x1024FC; // 4 0x03 r/w Touch-Screen Settle Time, n x 6 Clocks
+ static constexpr uint32_t TOUCH_OVERSAMPLE = 0x102500; // 4 0x07 r/w Touch-Screen Oversample Factor
+ static constexpr uint32_t TOUCH_RZTHRESH = 0x102504; // 16 0xFFFF r/w Touch-Screen Resistance Threshold
+ static constexpr uint32_t TOUCH_RAW_XY = 0x102508; // 32 - r Touch-Screen Raw (x-MSB16; y-LSB16)
+ static constexpr uint32_t TOUCH_RZ = 0x10250C; // 16 - r Touch-Screen Resistance
+ static constexpr uint32_t TOUCH_SCREEN_XY = 0x102510; // 32 - r Touch-Screen Screen (x-MSB16; y-LSB16)
+ static constexpr uint32_t TOUCH_TAG_XY = 0x102514; // 32 - r Touch-Screen Tag 0 Lookup (x-MSB16; y-LSB16)
+ static constexpr uint32_t TOUCH_TAG = 0x102518; // 8 - r Touch-Screen Tag 0 Result
+ static constexpr uint32_t TOUCH_TRANSFORM_A = 0x10251C; // 32 0x00010000 r/w Touch-Screen Transform Coefficient A (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_B = 0x102520; // 32 0x00000000 r/w Touch-Screen Transform Coefficient B (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_C = 0x102524; // 32 0x00000000 r/w Touch-Screen Transform Coefficient C (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_D = 0x102528; // 32 0x00000000 r/w Touch-Screen Transform Coefficient D (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_E = 0x10252C; // 32 0x00010000 r/w Touch-Screen Transform Coefficient E (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_F = 0x102530; // 32 0x00000000 r/w Touch-Screen Transform Coefficient F (s15.16)
+ // Reserved Addresses 0x102434 - 0x102470
+ static constexpr uint32_t TOUCH_DIRECT_XY = 0x102574; // 32 - r Touch-Screen Direct Conversions XY (x-MSB16; y-LSB16)
+ static constexpr uint32_t TOUCH_DIRECT_Z1Z2 = 0x102578; // 32 - r Touch-Screen Direct Conversions Z (z1-MSB16; z2-LSB16)
+ static constexpr uint32_t TRACKER = 0x109000; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft810.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft810.h
new file mode 100644
index 0000000..e57d11c
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft810.h
@@ -0,0 +1,187 @@
+/*********************
+ * registers_ft810.h *
+ *********************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+/****************************************************************************
+ * This header defines registers for the FTDI FT810 LCD Driver chip. *
+ ****************************************************************************/
+
+/*******************************************************************************
+ * FT810 *
+ * *
+ * START END ADDR SIZE NAME DESCRIPTION *
+ * *
+ * 0x000000 0x0FFFFF 1024 kB RAM_G Main Graphics RAM (0 to 1048572) *
+ * *
+ * 0x0C0000 0x0C0003 4 B ROM_CHIPID [0:1] 0x800 Chip Id *
+ * [1:2] 0x0100 Vers ID *
+ * *
+ * 0x1E0000 0x2FFFFB 1152 kB ROM_FONT Font table and bitmap *
+ * *
+ * 0x201EE0 0x2029DC 2812 B ROM_FONT_ROOT ROM font table *
+ * *
+ * 0x2FFFFC 0x2FFFFF 4 B ROM_FONT_ADDR Font table pointer address *
+ * *
+ * 0x300000 0x301FFF 8 kB RAM_DL Display List RAM *
+ * *
+ * 0x302000 0x302FFF 4 kB * Registers *
+ * *
+ * 0x308000 0x308FFF 4 kB RAM_CMD Command Buffer *
+ * *
+ *******************************************************************************/
+
+#pragma once
+
+namespace FTDI {
+ struct ft810_memory_map {
+ // MEMORY LOCATIONS FT810
+ static constexpr uint32_t RAM_G = 0x000000; // Main Graphics RAM
+ static constexpr uint32_t ROM_CHIPID = 0x0C0000; // Chip ID/Version ID
+ static constexpr uint32_t ROM_FONT = 0x1E0000; // Font ROM
+ static constexpr uint32_t ROM_FONT_ADDR = 0x2FFFFC; // Font Table Pointer
+ static constexpr uint32_t RAM_DL = 0x300000; // Display List RAM
+ static constexpr uint32_t RAM_REG = 0x302000; // Registers
+ static constexpr uint32_t RAM_CMD = 0x308000; // Command Buffer
+
+ static constexpr uint32_t RAM_G_SIZE = 1024*1024L; // 1024k
+ };
+
+ struct ft810_registers {
+ // REGISTERS AND ADDRESSES FT810
+
+ // REGISTER ADDRESS SIZE RESET VALUE TYPE DESCRIPTION
+
+ static constexpr uint32_t ID = 0x302000; // 8 0x7C r Identification Register, Always 0x7C
+ static constexpr uint32_t FRAMES = 0x302004; // 32 0x00000000 r Frame Counter, Since Reset
+ static constexpr uint32_t CLOCK = 0x302008; // 32 0x00000000 r Clock cycles, Since Reset
+ static constexpr uint32_t FREQUENCY = 0x30200C; // 28 0x03938700 r/w Main Clock Frequency
+ static constexpr uint32_t RENDERMODE = 0x302010; // 1 0x00 r/w Rendering Mode: 0 = normal, 1 = single-line
+ static constexpr uint32_t SNAPY = 0x302014; // 11 0x0000 r/w Scan Line Select for RENDERMODE 1
+ static constexpr uint32_t SNAPSHOT = 0x302018; // 1 - r Trigger for RENDERMODE 1
+ static constexpr uint32_t SNAPFORMAT = 0x30201C; // 6 0x20 r/w Pixel Format for Scanline Readout
+ static constexpr uint32_t CPURESET = 0x302020; // 3 0x02 r/w RESET Bit2 Audio - Bit1 Touch - Bit0 Graphics
+ static constexpr uint32_t TAP_CRC = 0x302024; // 32 - r Live Video Tap
+ static constexpr uint32_t TAP_MASK = 0x302028; // 32 0xFFFFFFFF r/w Live Video Tap Mask
+ static constexpr uint32_t HCYCLE = 0x30202C; // 12 0x224 r/w Horizontal Total Cycle Count
+ static constexpr uint32_t HOFFSET = 0x302030; // 12 0x02B r/w Horizontal Display Start Offset
+ static constexpr uint32_t HSIZE = 0x302034; // 12 0x1E0 r/w Horizontal Display Pixel Count
+ static constexpr uint32_t HSYNC0 = 0x302038; // 12 0x000 r/w Horizontal Sync Fall Offset
+ static constexpr uint32_t HSYNC1 = 0x30203C; // 12 0x029 r/w Horizontal Sync Rise Offset
+ static constexpr uint32_t VCYCLE = 0x302040; // 12 0x124 r/w Vertical Total Cycle Count
+ static constexpr uint32_t VOFFSET = 0x302044; // 12 0x00C r/w Vertical Display Start Offset
+ static constexpr uint32_t VSIZE = 0x302048; // 12 0x110 r/w Vertical Display Line Count
+ static constexpr uint32_t VSYNC0 = 0x30204C; // 10 0x000 r/w Vertical Sync Fall Offset
+ static constexpr uint32_t VSYNC1 = 0x302050; // 10 0x00A r/w Vertical Sync Rise Offset
+ static constexpr uint32_t DLSWAP = 0x302054; // 2 0x00 r/w Display List Swap Control
+ static constexpr uint32_t ROTATE = 0x302058; // 3 0x00 r/w Screen 90,180, 270 degree rotate
+ static constexpr uint32_t OUTBITS = 0x30205C; // 9 0x1B6 r/w Output Resolution, 3x3x3 Bits
+ static constexpr uint32_t DITHER = 0x302060; // 1 0x01 r/w Output Dither Enable
+ static constexpr uint32_t SWIZZLE = 0x302064; // 4 0x00 r/w Output RGB Swizzle, Pin Change for PCB Routing
+ static constexpr uint32_t CSPREAD = 0x302068; // 1 0x01 r/w Output Clock Spreading Enable
+ static constexpr uint32_t PCLK_POL = 0x30206C; // 1 0x00 r/w PCLK Polarity: 0 = Rising Edge, 1 = Falling Edge
+ static constexpr uint32_t PCLK = 0x302070; // 8 0x00 r/w PCLK Frequency Divider, 0 = Disable Clock
+ static constexpr uint32_t TAG_X = 0x302074; // 11 0x000 r/w Tag Query X Coordinate
+ static constexpr uint32_t TAG_Y = 0x302078; // 11 0x000 r/w Tag Query Y Coordinate
+ static constexpr uint32_t TAG = 0x30207C; // 8 0x00 r Tag Query Result
+ static constexpr uint32_t VOL_PB = 0x302080; // 8 0xFF r/w Audio Playback Volume
+ static constexpr uint32_t VOL_SOUND = 0x302084; // 8 0xFF r/w Audio Synthesizer Volume
+ static constexpr uint32_t SOUND = 0x302088; // 16 0x0000 r/w Audio Sound Effect Select
+ static constexpr uint32_t PLAY = 0x30208C; // 1 0x00 r/w Audio Start Effect Playback
+ static constexpr uint32_t GPIO_DIR = 0x302090; // 8 0x80 r/w GPIO Pin Direction: 0 = Input , 1 = Output
+ static constexpr uint32_t GPIO = 0x302094; // 8 0x00 r/w GPIO Pin Values for 0, 1, 7 Drive Strength 2, 3, 4, 5, 6
+ static constexpr uint32_t GPIOX_DIR = 0x302098; // 16 0x8000 r/w Extended GPIO Pin Direction
+ static constexpr uint32_t GPIOX = 0x30209C; // 16 0x0080 r/w Extended GPIO Pin Values
+ // Reserved Addr 0x3020A0
+ // Reserved Addr 0x3020A4
+ static constexpr uint32_t INT_FLAGS = 0x3020A8; // 8 0x00 r Interrupt Flags, Clear by Reading
+ static constexpr uint32_t INT_EN = 0x3020AC; // 1 0x00 r/w Global Interrupt Enable
+ static constexpr uint32_t INT_MASK = 0x3020B0; // 8 0xFF r/w Interrupt Enable Mask
+ static constexpr uint32_t PLAYBACK_START = 0x3020B4; // 20 0x00000 r/w Audio Playback RAM Start Address
+ static constexpr uint32_t PLAYBACK_LENGTH = 0x3020B8; // 20 0x00000 r/w Audio Playback Sample Length (Bytes)
+ static constexpr uint32_t PLAYBACK_READPTR = 0x3020BC; // 20 - r Audio Playback Read Pointer
+ static constexpr uint32_t PLAYBACK_FREQ = 0x3020C0; // 16 0x1F40 r/w Audio Playback Frequency (Hz)
+ static constexpr uint32_t PLAYBACK_FORMAT = 0x3020C4; // 2 0x00 r/w Audio Playback Format
+ static constexpr uint32_t PLAYBACK_LOOP = 0x3020C8; // 1 0x00 r/w Audio Playback Loop Enable
+ static constexpr uint32_t PLAYBACK_PLAY = 0x3020CC; // 1 0x00 r Audio Start Playback
+ static constexpr uint32_t PWM_HZ = 0x3020D0; // 14 0x00FA r/w Backlight PWM Frequency (Hz)
+ static constexpr uint32_t PWM_DUTY = 0x3020D4; // 8 0x80 r/w Backlight PWM Duty Cycle: 0 = 0%, 128 = 100%
+ static constexpr uint32_t MACRO_0 = 0x3020D8; // 32 0x00000000 r/w Display List Macro Command 0
+ static constexpr uint32_t MACRO_1 = 0x3020DC; // 32 0x00000000 r/w Display List Macro Command 1
+ // Reserved Addr 0x3020E0
+ // Reserved Addr 0x3020E4
+ // Reserved Addr 0x3020E8
+ // Reserved Addr 0x3020EC
+ // Reserved Addr 0x3020F0
+ // Reserved Addr 0x3020F4
+ static constexpr uint32_t CMD_READ = 0x3020F8; // 12 0x000 r/w Command Buffer Read Pointer
+ static constexpr uint32_t CMD_WRITE = 0x3020FC; // 12 0x000 r/w Command Buffer Write Pointer
+ static constexpr uint32_t CMD_DL = 0x302100; // 13 0x0000 r/w Command Display List Offset
+ static constexpr uint32_t TOUCH_MODE = 0x302104; // 2 0x03 r/w Touch-Screen Sampling Mode
+ static constexpr uint32_t TOUCH_ADC_MODE = 0x302108; // 1 0x01 r/w Select Single Ended or Differential Sampling
+ static constexpr uint32_t TOUCH_CHARGE = 0x30210C; // 16 0x1770 r/w Touch Screen Charge Time, n x 6 Clocks
+ static constexpr uint32_t TOUCH_SETTLE = 0x302110; // 4 0x03 r/w Touch-Screen Settle Time, n x 6 Clocks
+ static constexpr uint32_t TOUCH_OVERSAMPLE = 0x302114; // 4 0x07 r/w Touch-Screen Oversample Factor
+ static constexpr uint32_t TOUCH_RZTHRESH = 0x302118; // 16 0xFFFF r/w Touch-Screen Resistance Threshold
+ static constexpr uint32_t TOUCH_RAW_XY = 0x30211C; // 32 - r Touch-Screen Raw (x-MSB16; y-LSB16)
+ static constexpr uint32_t TOUCH_RZ = 0x302120; // 16 - r Touch-Screen Resistance
+ static constexpr uint32_t TOUCH_SCREEN_XY = 0x302124; // 32 - r Touch-Screen Screen (x-MSB16; y-LSB16)
+ static constexpr uint32_t TOUCH_TAG_XY = 0x302128; // 32 - r Touch-Screen Tag 0 Lookup (x-MSB16; y-LSB16)
+ static constexpr uint32_t TOUCH_TAG = 0x30212C; // 8 - r Touch-Screen Tag 0 Result
+ static constexpr uint32_t TOUCH_TAG1_XY = 0x302130; // 32 - r Touch-Screen Tag 1 Lookup
+ static constexpr uint32_t TOUCH_TAG1 = 0x302134; // 8 - r Touch-Screen Tag 1 Result
+ static constexpr uint32_t TOUCH_TAG2_XY = 0x302138; // 32 - r Touch-Screen Tag 2 Lookup
+ static constexpr uint32_t TOUCH_TAG2 = 0x30213C; // 8 - r Touch-Screen Tag 2 Result
+ static constexpr uint32_t TOUCH_TAG3_XY = 0x302140; // 32 - r Touch-Screen Tag 3 Lookup
+ static constexpr uint32_t TOUCH_TAG3 = 0x302144; // 8 - r Touch-Screen Tag 3 Result
+ static constexpr uint32_t TOUCH_TAG4_XY = 0x302148; // 32 - r Touch-Screen Tag 4 Lookup
+ static constexpr uint32_t TOUCH_TAG4 = 0x30214C; // 8 - r Touch-Screen Tag 4 Result
+ static constexpr uint32_t TOUCH_TRANSFORM_A = 0x302150; // 32 0x00010000 r/w Touch-Screen Transform Coefficient A (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_B = 0x302154; // 32 0x00000000 r/w Touch-Screen Transform Coefficient B (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_C = 0x302158; // 32 0x00000000 r/w Touch-Screen Transform Coefficient C (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_D = 0x30215C; // 32 0x00000000 r/w Touch-Screen Transform Coefficient D (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_E = 0x302160; // 32 0x00010000 r/w Touch-Screen Transform Coefficient E (s15.16)
+ static constexpr uint32_t TOUCH_TRANSFORM_F = 0x302164; // 32 0x00000000 r/w Touch-Screen Transform Coefficient F (s15.16)
+ static constexpr uint32_t TOUCH_CONFIG = 0x302168; // 16 0x8381 r/w Touch Configuration
+ static constexpr uint32_t CTOUCH_TOUCH4_X = 0x30216C; // 16 - r Extended Mode Touch Screen
+ // Reserved Addresses 0x302170
+ static constexpr uint32_t BIST_EN = 0x302174; // 1 0 r/w BIST Memory Mapping Enable
+ // Reserved Addr 0x302178
+ // Reserved Addr 0x30217C
+ static constexpr uint32_t TRIM = 0x302180; // 8 0 r/w Internal Clock Trimming
+ static constexpr uint32_t ANA_COMP = 0x302184; // 8 0 r/w Analog Control Register
+ static constexpr uint32_t SPI_WIDTH = 0x302188; // 3 0 r/w QSPI Bus Width Setting
+ static constexpr uint32_t TOUCH_DIRECT_XY = 0x30218C; // 32 - r Touch-Screen Direct Conversions XY (x-MSB16; y-LSB16)
+ static constexpr uint32_t TOUCH_DIRECT_Z1Z2 = 0x302190; // 32 - r Touch-Screen Direct Conversions Z (z1-MSB16; z2-LSB16)
+ // Reserved Addresses 0x302194 - 0x302560
+ static constexpr uint32_t DATESTAMP = 0x320564; // 128 - r Stamp Date Code
+ static constexpr uint32_t CMDB_SPACE = 0x302574; // 12 0xFFC r/w Command DL Space Available
+ static constexpr uint32_t CMDB_WRITE = 0x302578; // 32 0 w Command DL Write
+
+ static constexpr uint32_t TRACKER = 0x309000; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
+ static constexpr uint32_t TRACKER_1 = 0x309004; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
+ static constexpr uint32_t TRACKER_2 = 0x309008; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
+ static constexpr uint32_t TRACKER_3 = 0x30900C; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
+ static constexpr uint32_t TRACKER_4 = 0x309010; // 32 0x00000000 r/w Track Register (Track Value MSB16; Tag Value - LSB8)
+
+ static constexpr uint32_t MEDIAFIFO_READ = 0x309014; // 32 0x00000000 r/w Media FIFO read pointer
+ static constexpr uint32_t MEDIAFIFO_WRITE = 0x309018; // 32 0x00000000 r/w Media FIFO write pointer
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h
new file mode 100644
index 0000000..0c600fa
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h
@@ -0,0 +1,142 @@
+/*****************
+ * resolutions.h *
+ *****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2019 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/***
+ * The FT8xx has odd registers that don't correspond to timing values in
+ * display datasheets. This macro computes the register values using the
+ * formulas given in the document:
+ *
+ * Bridgetek Application Note
+ * AN_336 FT8xx
+ * Selecting an LCD Display
+ * Version 2.1
+ * Issue Date: 2017-11-14
+ */
+#define COMPUTE_REGS_FROM_DATASHEET \
+ constexpr uint16_t Hoffset = thfp + thb - 1; \
+ constexpr uint16_t Hcycle = th; \
+ constexpr uint16_t Hsync0 = thfp - 1 ; \
+ constexpr uint16_t Hsync1 = thfp + thpw - 1; \
+ constexpr uint16_t Voffset = tvfp + tvb - 1; \
+ constexpr uint16_t Vcycle = tv; \
+ constexpr uint16_t Vsync0 = tvfp - 1; \
+ constexpr uint16_t Vsync1 = tvfp + tvpw - 1; \
+ static_assert(thfp + thb + Hsize == th, "Mismatch in display th"); \
+ static_assert(tvfp + tvb + Vsize == tv, "Mismatch in display tv")
+
+#if ENABLED(TOUCH_UI_320x240)
+ namespace FTDI {
+ constexpr uint8_t Pclk = 8;
+ constexpr uint8_t Pclkpol = 0;
+ constexpr uint16_t Hsize = 320;
+ constexpr uint16_t Vsize = 240;
+ constexpr uint16_t Vsync0 = 0;
+ constexpr uint16_t Vsync1 = 2;
+ constexpr uint16_t Voffset = 13;
+ constexpr uint16_t Vcycle = 263;
+ constexpr uint16_t Hsync0 = 0;
+ constexpr uint16_t Hsync1 = 10;
+ constexpr uint16_t Hoffset = 70;
+ constexpr uint16_t Hcycle = 408;
+
+ constexpr uint32_t default_transform_a = 0x000054AD;
+ constexpr uint32_t default_transform_b = 0xFFFFFF52;
+ constexpr uint32_t default_transform_c = 0xFFF7F6E4;
+ constexpr uint32_t default_transform_d = 0x00000065;
+ constexpr uint32_t default_transform_e = 0xFFFFBE3B;
+ constexpr uint32_t default_transform_f = 0x00F68E75;
+ }
+
+#elif defined(TOUCH_UI_480x272)
+ namespace FTDI {
+ constexpr uint8_t Pclk = 7;
+ constexpr uint8_t Pclkpol = 1;
+ constexpr uint16_t Hsize = 480;
+ constexpr uint16_t Vsize = 272;
+
+ constexpr uint16_t th = 525; // One horizontal line
+ constexpr uint16_t thfp = 43; // HS Front porch
+ constexpr uint16_t thb = 2; // HS Back porch (blanking)
+ constexpr uint16_t thpw = 41; // HS pulse width
+
+ constexpr uint16_t tv = 286; // Vertical period time
+ constexpr uint16_t tvfp = 12; // VS Front porch
+ constexpr uint16_t tvb = 2; // VS Back porch (blanking)
+ constexpr uint16_t tvpw = 10; // VS pulse width
+
+ COMPUTE_REGS_FROM_DATASHEET;
+
+ constexpr uint32_t default_transform_a = 0x00008100;
+ constexpr uint32_t default_transform_b = 0x00000000;
+ constexpr uint32_t default_transform_c = 0xFFF18000;
+ constexpr uint32_t default_transform_d = 0x00000000;
+ constexpr uint32_t default_transform_e = 0xFFFFB100;
+ constexpr uint32_t default_transform_f = 0x0120D000;
+ }
+
+#elif defined(TOUCH_UI_800x480)
+ namespace FTDI {
+ #if defined(TOUCH_UI_800x480_GENERIC)
+ constexpr uint8_t Pclk = 2;
+ constexpr uint16_t Hsize = 800;
+ constexpr uint16_t Vsize = 480;
+
+ constexpr uint16_t Vsync0 = 0;
+ constexpr uint16_t Vsync1 = 3;
+ constexpr uint16_t Voffset = 32;
+ constexpr uint16_t Vcycle = 525;
+ constexpr uint16_t Hsync0 = 0;
+ constexpr uint16_t Hsync1 = 48;
+ constexpr uint16_t Hoffset = 88;
+ constexpr uint16_t Hcycle = 928;
+ #else
+ constexpr uint8_t Pclk = 3;
+ constexpr uint8_t Pclkpol = 1;
+ constexpr uint16_t Hsize = 800;
+ constexpr uint16_t Vsize = 480;
+
+ constexpr uint16_t th = 1056; // One horizontal line
+ constexpr uint16_t thfp = 210; // HS Front porch
+ constexpr uint16_t thb = 46; // HS Back porch (blanking)
+ constexpr uint16_t thpw = 23; // HS pulse width
+
+ constexpr uint16_t tv = 525; // Vertical period time
+ constexpr uint16_t tvfp = 22; // VS Front porch
+ constexpr uint16_t tvb = 23; // VS Back porch (blanking)
+ constexpr uint16_t tvpw = 10; // VS pulse width
+
+ COMPUTE_REGS_FROM_DATASHEET;
+
+ constexpr uint32_t default_transform_a = 0x0000D8B9;
+ constexpr uint32_t default_transform_b = 0x00000124;
+ constexpr uint32_t default_transform_c = 0xFFE23926;
+ constexpr uint32_t default_transform_d = 0xFFFFFF51;
+ constexpr uint32_t default_transform_e = 0xFFFF7E4F;
+ constexpr uint32_t default_transform_f = 0x01F0AF70;
+ #endif
+ }
+
+#else
+ #error "Unknown or no TOUCH_UI_FTDI_EVE display resolution specified. To add a display resolution, modify 'ftdi_eve_resolutions.h'."
+#endif
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.cpp
new file mode 100644
index 0000000..30f778e
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.cpp
@@ -0,0 +1,175 @@
+/***********
+ * spi.cpp *
+ ***********/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_basic.h"
+
+#ifdef FTDI_BASIC
+
+/********************************* SPI Functions *********************************/
+
+namespace FTDI {
+
+ #ifndef CLCD_USE_SOFT_SPI
+ #ifdef CLCD_SPI_BUS
+ SPIClass EVE_SPI(CLCD_SPI_BUS);
+ #endif
+ #ifndef CLCD_HW_SPI_SPEED
+ #define CLCD_HW_SPI_SPEED 8000000 >> SD_SPI_SPEED
+ #endif
+ SPISettings SPI::spi_settings(CLCD_HW_SPI_SPEED, MSBFIRST, SPI_MODE0);
+ #endif
+
+ void SPI::spi_init() {
+ SET_OUTPUT(CLCD_MOD_RESET); // Module Reset (a.k.a. PD, not SPI)
+ WRITE(CLCD_MOD_RESET, 0); // start with module in power-down
+
+ SET_OUTPUT(CLCD_SPI_CS);
+ WRITE(CLCD_SPI_CS, 1);
+
+ #ifdef CLCD_SPI_EXTRA_CS
+ SET_OUTPUT(CLCD_SPI_EXTRA_CS);
+ WRITE(CLCD_SPI_EXTRA_CS, 1);
+ #endif
+
+ #ifdef SPI_FLASH_SS
+ SET_OUTPUT(SPI_FLASH_SS);
+ WRITE(SPI_FLASH_SS, 1);
+ #endif
+
+ #ifdef CLCD_USE_SOFT_SPI
+ SET_OUTPUT(CLCD_SOFT_SPI_MOSI);
+ WRITE(CLCD_SOFT_SPI_MOSI, 1);
+
+ SET_OUTPUT(CLCD_SOFT_SPI_SCLK);
+ WRITE(CLCD_SOFT_SPI_SCLK, 0);
+
+ SET_INPUT_PULLUP(CLCD_SOFT_SPI_MISO);
+ #else
+ SPI_OBJ.begin();
+ #endif
+ }
+
+ #ifdef CLCD_USE_SOFT_SPI
+ uint8_t SPI::_soft_spi_xfer(uint8_t spiOutByte) {
+ uint8_t spiIndex = 0x80;
+ uint8_t spiInByte = 0;
+ uint8_t k;
+
+ noInterrupts();
+ for (k = 0; k < 8; k++) { // Output and Read each bit of spiOutByte and spiInByte
+ WRITE(CLCD_SOFT_SPI_MOSI, (spiOutByte & spiIndex) ? 1 : 0); // Output MOSI Bit
+ WRITE(CLCD_SOFT_SPI_SCLK, 1); // Pulse Clock
+ if (READ(CLCD_SOFT_SPI_MISO)) spiInByte |= spiIndex; // MISO changes on the falling edge of clock, so sample it before
+ WRITE(CLCD_SOFT_SPI_SCLK, 0);
+ spiIndex >>= 1;
+ }
+ interrupts();
+ return spiInByte;
+ }
+ #endif
+
+ #ifdef CLCD_USE_SOFT_SPI
+ void SPI::_soft_spi_send(uint8_t spiOutByte) {
+ uint8_t k, spiIndex = 0x80;
+
+ noInterrupts();
+ for (k = 0; k < 8; k++) { // Output each bit of spiOutByte
+ WRITE(CLCD_SOFT_SPI_MOSI, (spiOutByte & spiIndex) ? 1 : 0); // Output MOSI Bit
+ WRITE(CLCD_SOFT_SPI_SCLK, 1); // Pulse Clock
+ WRITE(CLCD_SOFT_SPI_SCLK, 0);
+ spiIndex >>= 1;
+ }
+ interrupts();
+ }
+ #endif
+
+ void SPI::spi_read_bulk(void *data, uint16_t len) {
+ uint8_t *p = (uint8_t *)data;
+ while (len--) *p++ = spi_recv();
+ }
+
+ bool SPI::spi_verify_bulk(const void *data, uint16_t len) {
+ const uint8_t *p = (const uint8_t *)data;
+ while (len--) if (*p++ != spi_recv()) return false;
+ return true;
+ }
+
+ // CLCD SPI - Chip Select
+ void SPI::spi_ftdi_select() {
+ #ifndef CLCD_USE_SOFT_SPI
+ SPI_OBJ.beginTransaction(spi_settings);
+ #endif
+ WRITE(CLCD_SPI_CS, 0);
+ #ifdef CLCD_SPI_EXTRA_CS
+ WRITE(CLCD_SPI_EXTRA_CS, 0);
+ #endif
+ delayMicroseconds(1);
+ }
+
+ // CLCD SPI - Chip Deselect
+ void SPI::spi_ftdi_deselect() {
+ WRITE(CLCD_SPI_CS, 1);
+ #ifdef CLCD_SPI_EXTRA_CS
+ WRITE(CLCD_SPI_EXTRA_CS, 1);
+ #endif
+ #ifndef CLCD_USE_SOFT_SPI
+ SPI_OBJ.endTransaction();
+ #endif
+ }
+
+ #ifdef SPI_FLASH_SS
+ // Serial SPI Flash SPI - Chip Select
+ void SPI::spi_flash_select() {
+ #ifndef CLCD_USE_SOFT_SPI
+ SPI_OBJ.beginTransaction(spi_settings);
+ #endif
+ WRITE(SPI_FLASH_SS, 0);
+ delayMicroseconds(1);
+ }
+
+ // Serial SPI Flash SPI - Chip Deselect
+ void SPI::spi_flash_deselect() {
+ WRITE(SPI_FLASH_SS, 1);
+ #ifndef CLCD_USE_SOFT_SPI
+ SPI_OBJ.endTransaction();
+ #endif
+ }
+ #endif
+
+ // Not really a SPI signal...
+ void SPI::ftdi_reset() {
+ WRITE(CLCD_MOD_RESET, 0);
+ delay(6); /* minimum time for power-down is 5ms */
+ WRITE(CLCD_MOD_RESET, 1);
+ delay(21); /* minimum time to allow from rising PD_N to first access is 20ms */
+ }
+
+ // Not really a SPI signal...
+ void SPI::test_pulse() {
+ #ifdef CLCD_AUX_0
+ WRITE(CLCD_AUX_0, 1);
+ delayMicroseconds(10);
+ WRITE(CLCD_AUX_0, 0);
+ #endif
+ }
+}
+#endif // FTDI_BASIC
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.h
new file mode 100644
index 0000000..7adf7e9
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.h
@@ -0,0 +1,136 @@
+/*********
+ * spi.h *
+ *********/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#ifndef CLCD_USE_SOFT_SPI
+ #include
+#endif
+
+namespace FTDI {
+
+ #if !defined(CLCD_SPI_BUS) || defined(CLCD_USE_SOFT_SPI)
+ #define SPI_OBJ ::SPI
+ #else
+ extern SPIClass EVE_SPI;
+ #define SPI_OBJ EVE_SPI
+ #endif
+
+ namespace SPI {
+ #ifndef CLCD_USE_SOFT_SPI
+ extern SPISettings spi_settings;
+ #endif
+
+ uint8_t _soft_spi_xfer (uint8_t val);
+ void _soft_spi_send (uint8_t val);
+
+ void spi_init ();
+
+ void spi_ftdi_select ();
+ void spi_ftdi_deselect ();
+
+ void spi_flash_select ();
+ void spi_flash_deselect ();
+
+ inline uint8_t spi_recv() {
+ #ifdef CLCD_USE_SOFT_SPI
+ return _soft_spi_xfer(0x00);
+ #else
+ return SPI_OBJ.transfer(0x00);
+ #endif
+ };
+
+ inline void spi_send (uint8_t val) {
+ #ifdef CLCD_USE_SOFT_SPI
+ _soft_spi_send(val);
+ #else
+ SPI_OBJ.transfer(val);
+ #endif
+ };
+
+ inline void spi_write_8 (uint8_t val) {spi_send(val);};
+ inline uint8_t spi_read_8 () {return spi_recv();};
+
+ namespace least_significant_byte_first {
+ inline void spi_write_16 (uint16_t val) {spi_send(val >> 0);
+ spi_send(val >> 8);};
+ inline void spi_write_32 (uint32_t val) {spi_send(val >> 0);
+ spi_send(val >> 8);
+ spi_send(val >> 16);
+ spi_send(val >> 24);};
+
+ inline uint8_t spi_read_8 () {return spi_recv();};
+ inline uint16_t spi_read_16 () {return (((uint16_t) spi_recv()) << 0) |
+ (((uint16_t) spi_recv()) << 8);};
+ inline uint32_t spi_read_32 () {return (((uint32_t) spi_recv()) << 0) |
+ (((uint32_t) spi_recv()) << 8) |
+ (((uint32_t) spi_recv()) << 16) |
+ (((uint32_t) spi_recv()) << 24);};
+ }
+
+ namespace most_significant_byte_first {
+ inline void spi_write_16 (uint16_t val) {spi_send(val >> 8);
+ spi_send(val >> 0);};
+ inline void spi_write_24 (uint32_t val) {spi_send(val >> 16);
+ spi_send(val >> 8);
+ spi_send(val >> 0);};
+ inline void spi_write_32 (uint32_t val) {spi_send(val >> 24);
+ spi_send(val >> 16);
+ spi_send(val >> 8);
+ spi_send(val >> 0);};
+
+ inline uint16_t spi_read_16 () {return (((uint16_t) spi_recv()) << 8) |
+ (((uint16_t) spi_recv()) << 0);};
+ inline uint32_t spi_read_32 () {return (((uint32_t) spi_recv()) << 24) |
+ (((uint32_t) spi_recv()) << 16) |
+ (((uint32_t) spi_recv()) << 8) |
+ (((uint32_t) spi_recv()) << 0);};
+ }
+
+ inline uint8_t ram_write(const uint8_t *p) {return *p;}
+ inline uint8_t pgm_write(const uint8_t *p) {return pgm_read_byte(p);}
+
+ typedef uint8_t (*bulk_write_op)(const uint8_t*);
+
+ // Generic template for function for writing multiple bytes, plus padding bytes.
+ // The template parameter op is an inlineable function which is applied to each byte.
+
+ template
+ void spi_write_bulk(const void *data, uint16_t len, uint8_t padding) {
+ const uint8_t *p = (const uint8_t *)data;
+ while (len--) spi_send(byte_op(p++));
+ while (padding--) spi_send(0);
+ }
+
+ template
+ void spi_write_bulk(const void *data, uint16_t len) {
+ const uint8_t *p = (const uint8_t *)data;
+ while (len--) spi_send(byte_op(p++));
+ }
+
+ void spi_read_bulk( void *data, uint16_t len);
+ bool spi_verify_bulk(const void *data, uint16_t len);
+
+ void ftdi_reset();
+ void test_pulse();
+ }
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h
new file mode 100644
index 0000000..6b2dc9e
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h
@@ -0,0 +1,330 @@
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#include "../config.h"
+
+#ifdef __MARLIN_FIRMWARE__
+
+ // Marlin will define the I/O functions for us
+ #if ENABLED(TOUCH_UI_FTDI_EVE)
+ #define FTDI_BASIC
+ #define FTDI_EXTENDED
+ #endif
+
+#else // !__MARLIN_FIRMWARE__
+
+ #include
+
+ #ifndef CLCD_USE_SOFT_SPI
+ #include
+ #endif
+
+ namespace fast_io {
+
+ template
+ struct port_pin {
+ typedef port_t port;
+ static void set_high() {port::port() = (port::port() | bits);}
+ static void set_low() {port::port() = (port::port() & (~bits));}
+ static void set_input() {port::ddr() = (port::ddr() & (~bits));}
+ static void set_input_pullup() {set_input(); set_high();}
+ static void set_output() {port::ddr() = (port::ddr() | bits);}
+ static uint8_t read() {return port::pin() & bits;}
+ static void write(bool v) {if (v) set_high(); else set_low();}
+ };
+
+ #define MAKE_AVR_PORT_PINS(ID) \
+ struct port_##ID { \
+ static volatile uint8_t &pin() {return PIN##ID;}; \
+ static volatile uint8_t &port() {return PORT##ID;}; \
+ static volatile uint8_t &ddr() {return DDR##ID;}; \
+ }; \
+ typedef port_pin AVR_##ID##0; \
+ typedef port_pin AVR_##ID##1; \
+ typedef port_pin AVR_##ID##2; \
+ typedef port_pin AVR_##ID##3; \
+ typedef port_pin AVR_##ID##4; \
+ typedef port_pin AVR_##ID##5; \
+ typedef port_pin AVR_##ID##6; \
+ typedef port_pin AVR_##ID##7;
+
+ #ifdef PORTA
+ MAKE_AVR_PORT_PINS(A);
+ #endif
+ #ifdef PORTB
+ MAKE_AVR_PORT_PINS(B);
+ #endif
+ #ifdef PORTC
+ MAKE_AVR_PORT_PINS(C);
+ #endif
+ #ifdef PORTD
+ MAKE_AVR_PORT_PINS(D);
+ #endif
+ #ifdef PORTE
+ MAKE_AVR_PORT_PINS(E);
+ #endif
+ #ifdef PORTF
+ MAKE_AVR_PORT_PINS(F);
+ #endif
+ #ifdef PORTG
+ MAKE_AVR_PORT_PINS(G);
+ #endif
+ #ifdef PORTH
+ MAKE_AVR_PORT_PINS(H);
+ #endif
+ #ifdef PORTJ
+ MAKE_AVR_PORT_PINS(J);
+ #endif
+ #ifdef PORTK
+ MAKE_AVR_PORT_PINS(K);
+ #endif
+ #ifdef PORTL
+ MAKE_AVR_PORT_PINS(L);
+ #endif
+ #ifdef PORTQ
+ MAKE_AVR_PORT_PINS(Q);
+ #endif
+ #ifdef PORTR
+ MAKE_AVR_PORT_PINS(R);
+ #endif
+
+ #undef MAKE_AVR_PORT_PINS
+
+ template
+ struct arduino_digital_pin {
+ static constexpr uint8_t pin = p;
+ static void set_high() {digitalWrite(p, HIGH);}
+ static void set_low() {digitalWrite(p, LOW);}
+ static void set_input() {pinMode(p, INPUT);}
+ static void set_input_pullup() {pinMode(p, INPUT_PULLUP);}
+ static void set_output() {pinMode(p, OUTPUT);}
+ static uint8_t read() {return digitalRead(p);}
+ static void write(bool v) {digitalWrite(p, v ? HIGH : LOW);}
+ };
+
+ #define MAKE_ARDUINO_PINS(ID) typedef arduino_digital_pin ARDUINO_DIGITAL_##ID;
+ MAKE_ARDUINO_PINS( 0);
+ MAKE_ARDUINO_PINS( 1);
+ MAKE_ARDUINO_PINS( 2);
+ MAKE_ARDUINO_PINS( 3);
+ MAKE_ARDUINO_PINS( 4);
+ MAKE_ARDUINO_PINS( 5);
+ MAKE_ARDUINO_PINS( 6);
+ MAKE_ARDUINO_PINS( 7);
+ MAKE_ARDUINO_PINS( 8);
+ MAKE_ARDUINO_PINS( 9);
+ MAKE_ARDUINO_PINS(10);
+ MAKE_ARDUINO_PINS(11);
+ MAKE_ARDUINO_PINS(12);
+ MAKE_ARDUINO_PINS(13);
+ MAKE_ARDUINO_PINS(14);
+ MAKE_ARDUINO_PINS(15);
+ MAKE_ARDUINO_PINS(16);
+ MAKE_ARDUINO_PINS(17);
+ MAKE_ARDUINO_PINS(18);
+ MAKE_ARDUINO_PINS(19);
+ MAKE_ARDUINO_PINS(10);
+ MAKE_ARDUINO_PINS(21);
+ MAKE_ARDUINO_PINS(22);
+ MAKE_ARDUINO_PINS(23);
+ MAKE_ARDUINO_PINS(24);
+ MAKE_ARDUINO_PINS(25);
+ MAKE_ARDUINO_PINS(26);
+ MAKE_ARDUINO_PINS(27);
+ MAKE_ARDUINO_PINS(28);
+ MAKE_ARDUINO_PINS(29);
+ MAKE_ARDUINO_PINS(30);
+ MAKE_ARDUINO_PINS(31);
+ MAKE_ARDUINO_PINS(32);
+ MAKE_ARDUINO_PINS(33);
+ MAKE_ARDUINO_PINS(34);
+ MAKE_ARDUINO_PINS(35);
+ MAKE_ARDUINO_PINS(36);
+ MAKE_ARDUINO_PINS(37);
+ MAKE_ARDUINO_PINS(38);
+ MAKE_ARDUINO_PINS(39);
+ MAKE_ARDUINO_PINS(40);
+ MAKE_ARDUINO_PINS(41);
+ MAKE_ARDUINO_PINS(42);
+ MAKE_ARDUINO_PINS(43);
+ MAKE_ARDUINO_PINS(44);
+ MAKE_ARDUINO_PINS(45);
+ MAKE_ARDUINO_PINS(46);
+ MAKE_ARDUINO_PINS(47);
+ MAKE_ARDUINO_PINS(48);
+ MAKE_ARDUINO_PINS(49);
+ MAKE_ARDUINO_PINS(50);
+ MAKE_ARDUINO_PINS(51);
+ MAKE_ARDUINO_PINS(52);
+ MAKE_ARDUINO_PINS(53);
+ #undef MAKE_ARDUINO_PINS
+ } // namespace fast_io
+
+ #define SET_INPUT(pin) fast_io::pin::set_input()
+ #define SET_INPUT_PULLUP(pin) do{ fast_io::pin::set_input(); fast_io::pin::set_high(); }while(0)
+ #define SET_INPUT_PULLDOWN SET_INPUT
+ #define SET_OUTPUT(pin) fast_io::pin::set_output()
+ #define READ(pin) fast_io::pin::read()
+ #define WRITE(pin, value) fast_io::pin::write(value)
+
+ #ifndef pgm_read_word_far
+ #define pgm_read_word_far pgm_read_word
+ #endif
+
+ #ifndef pgm_read_dword_far
+ #define pgm_read_dword_far pgm_read_dword
+ #endif
+
+ #ifndef pgm_read_ptr_far
+ #define pgm_read_ptr_far pgm_read_ptr
+ #endif
+
+ // Use NUM_ARGS(__VA_ARGS__) to get the number of variadic arguments
+ #define _NUM_ARGS(_,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
+ #define NUM_ARGS(V...) _NUM_ARGS(0,V,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
+
+ // SERIAL_ECHOPGM / SERIAL_ECHOPGM_P is used to output a key value pair. The key must be a string and the value can be anything
+ // Print up to 12 pairs of values. Odd elements auto-wrapped in PSTR().
+ #define __SEP_N(N,V...) _SEP_##N(V)
+ #define _SEP_N(N,V...) __SEP_N(N,V)
+ #define _SEP_1(PRE) SERIAL_ECHOPGM(PRE)
+ #define _SEP_2(PRE,V) do{ Serial.print(F(PRE)); Serial.print(V); }while(0)
+ #define _SEP_3(a,b,c) do{ _SEP_2(a,b); SERIAL_ECHOPGM(c); }while(0)
+ #define _SEP_4(a,b,V...) do{ _SEP_2(a,b); _SEP_2(V); }while(0)
+
+ // Print up to 1 pairs of values followed by newline
+ #define __SELP_N(N,V...) _SELP_##N(V)
+ #define _SELP_N(N,V...) __SELP_N(N,V)
+ #define _SELP_1(PRE) SERIAL_ECHOLNPGM(PRE)
+ #define _SELP_2(PRE,V) do{ Serial.print(F(PRE)); Serial.println(V); }while(0)
+ #define _SELP_3(a,b,c) do{ _SEP_2(a,b); SERIAL_ECHOLNPGM(c); }while(0)
+ #define _SELP_4(a,b,V...) do{ _SEP_2(a,b); _SELP_2(V); }while(0)
+ #define SERIAL_ECHO_START()
+ #define SERIAL_ECHOLNPGM(str) Serial.println(F(str))
+ #define SERIAL_ECHOPGM(str) Serial.print(F(str))
+ #define SERIAL_ECHO_MSG(V...) SERIAL_ECHOLNPGM(V)
+ #define SERIAL_ECHOLNPGM(V...) _SELP_N(NUM_ARGS(V),V)
+ #define SERIAL_ECHOPGM(str, val) do{ Serial.print(F(str)); Serial.print(val); }while(0)
+
+ #define safe_delay delay
+
+ // Define macros for compatibility
+
+ // Use NUM_ARGS(__VA_ARGS__) to get the number of variadic arguments
+ #define _NUM_ARGS(_,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
+ #define NUM_ARGS(V...) _NUM_ARGS(0,V,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
+
+ #define _CAT(a,V...) a##V
+ #define CAT(a,V...) _CAT(a,V)
+
+ #define FIRST(a,...) a
+ #define SECOND(a,b,...) b
+ #define THIRD(a,b,c,...) c
+
+ #define IS_PROBE(V...) SECOND(V, 0) // Get the second item passed, or 0
+ #define PROBE() ~, 1 // Second item will be 1 if this is passed
+ #define _NOT_0 PROBE()
+ #define NOT(x) IS_PROBE(_CAT(_NOT_, x)) // NOT('0') gets '1'. Anything else gets '0'.
+ #define _BOOL(x) NOT(NOT(x)) // _BOOL('0') gets '0'. Anything else gets '1'.
+
+ #define _DO_1(W,C,A) (_##W##_1(A))
+ #define _DO_2(W,C,A,B) (_##W##_1(A) C _##W##_1(B))
+ #define _DO_3(W,C,A,V...) (_##W##_1(A) C _DO_2(W,C,V))
+ #define _DO_4(W,C,A,V...) (_##W##_1(A) C _DO_3(W,C,V))
+ #define _DO_5(W,C,A,V...) (_##W##_1(A) C _DO_4(W,C,V))
+ #define _DO_6(W,C,A,V...) (_##W##_1(A) C _DO_5(W,C,V))
+ #define _DO_7(W,C,A,V...) (_##W##_1(A) C _DO_6(W,C,V))
+ #define _DO_8(W,C,A,V...) (_##W##_1(A) C _DO_7(W,C,V))
+ #define _DO_9(W,C,A,V...) (_##W##_1(A) C _DO_8(W,C,V))
+ #define _DO_10(W,C,A,V...) (_##W##_1(A) C _DO_9(W,C,V))
+ #define _DO_11(W,C,A,V...) (_##W##_1(A) C _DO_10(W,C,V))
+ #define _DO_12(W,C,A,V...) (_##W##_1(A) C _DO_11(W,C,V))
+ #define _DO_13(W,C,A,V...) (_##W##_1(A) C _DO_12(W,C,V))
+ #define _DO_14(W,C,A,V...) (_##W##_1(A) C _DO_13(W,C,V))
+ #define _DO_15(W,C,A,V...) (_##W##_1(A) C _DO_14(W,C,V))
+ #define _DO_16(W,C,A,V...) (_##W##_1(A) C _DO_15(W,C,V))
+ #define _DO_17(W,C,A,V...) (_##W##_1(A) C _DO_16(W,C,V))
+ #define _DO_18(W,C,A,V...) (_##W##_1(A) C _DO_17(W,C,V))
+ #define _DO_19(W,C,A,V...) (_##W##_1(A) C _DO_18(W,C,V))
+ #define _DO_20(W,C,A,V...) (_##W##_1(A) C _DO_19(W,C,V))
+ #define _DO_21(W,C,A,V...) (_##W##_1(A) C _DO_20(W,C,V))
+ #define _DO_22(W,C,A,V...) (_##W##_1(A) C _DO_21(W,C,V))
+ #define _DO_23(W,C,A,V...) (_##W##_1(A) C _DO_22(W,C,V))
+ #define _DO_24(W,C,A,V...) (_##W##_1(A) C _DO_23(W,C,V))
+ #define _DO_25(W,C,A,V...) (_##W##_1(A) C _DO_24(W,C,V))
+ #define _DO_26(W,C,A,V...) (_##W##_1(A) C _DO_25(W,C,V))
+ #define _DO_27(W,C,A,V...) (_##W##_1(A) C _DO_26(W,C,V))
+ #define _DO_28(W,C,A,V...) (_##W##_1(A) C _DO_27(W,C,V))
+ #define _DO_29(W,C,A,V...) (_##W##_1(A) C _DO_28(W,C,V))
+ #define _DO_30(W,C,A,V...) (_##W##_1(A) C _DO_29(W,C,V))
+ #define _DO_31(W,C,A,V...) (_##W##_1(A) C _DO_30(W,C,V))
+ #define _DO_32(W,C,A,V...) (_##W##_1(A) C _DO_31(W,C,V))
+ #define _DO_33(W,C,A,V...) (_##W##_1(A) C _DO_32(W,C,V))
+ #define _DO_34(W,C,A,V...) (_##W##_1(A) C _DO_33(W,C,V))
+ #define _DO_35(W,C,A,V...) (_##W##_1(A) C _DO_34(W,C,V))
+ #define _DO_36(W,C,A,V...) (_##W##_1(A) C _DO_35(W,C,V))
+ #define _DO_37(W,C,A,V...) (_##W##_1(A) C _DO_36(W,C,V))
+ #define _DO_38(W,C,A,V...) (_##W##_1(A) C _DO_37(W,C,V))
+ #define _DO_39(W,C,A,V...) (_##W##_1(A) C _DO_38(W,C,V))
+ #define _DO_40(W,C,A,V...) (_##W##_1(A) C _DO_39(W,C,V))
+ #define __DO_N(W,C,N,V...) _DO_##N(W,C,V)
+ #define _DO_N(W,C,N,V...) __DO_N(W,C,N,V)
+ #define DO(W,C,V...) _DO_N(W,C,NUM_ARGS(V),V)
+
+ #define _ISENA_ ~,1
+ #define _ISENA_1 ~,1
+ #define _ISENA_0x1 ~,1
+ #define _ISENA_true ~,1
+ #define _ISENA(V...) IS_PROBE(V)
+ #define _ENA_1(O) _ISENA(CAT(_IS,CAT(ENA_, O)))
+ #define _DIS_1(O) NOT(_ENA_1(O))
+ #define ENABLED(V...) DO(ENA,&&,V)
+ #define DISABLED(V...) DO(DIS,&&,V)
+
+ #define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION converted to '0' or '1'
+ #define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION converted to A or '0'
+ #define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION converted to A or '1'
+ #define TERN_(O,A) _TERN(_ENA_1(O),,A) // OPTION converted to A or ''
+ #define _TERN(E,V...) __TERN(_CAT(T_,E),V) // Prepend 'T_' to get 'T_0' or 'T_1'
+ #define __TERN(T,V...) ___TERN(_CAT(_NO,T),V) // Prepend '_NO' to get '_NOT_0' or '_NOT_1'
+ #define ___TERN(P,V...) THIRD(P,V) // If first argument has a comma, A. Else B.
+
+ #define IF_ENABLED TERN_
+ #define IF_DISABLED(O,A) _TERN(_ENA_1(O),,A)
+
+ #define ANY(V...) !DISABLED(V)
+ #define NONE(V...) DISABLED(V)
+ #define ALL(V...) ENABLED(V)
+ #define BOTH(V1,V2) ALL(V1,V2)
+ #define EITHER(V1,V2) ANY(V1,V2)
+
+ // Remove compiler warning on an unused variable
+ #ifndef UNUSED
+ #ifdef HAL_STM32
+ #define UNUSED(X) (void)X
+ #else
+ #define UNUSED(x) ((void)(x))
+ #endif
+ #endif
+
+#endif // !__MARLIN_FIRMWARE__
+
+#ifndef SD_SPI_SPEED
+ #define SD_SPI_SPEED SPI_FULL_SPEED
+#endif
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/adjuster_widget.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/adjuster_widget.cpp
new file mode 100644
index 0000000..470d380
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/adjuster_widget.cpp
@@ -0,0 +1,60 @@
+/***********************
+ * adjuster_widget.cpp *
+ ***********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2021 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+#define SUB_COLS 9
+#define SUB_ROWS 1
+#define VAL_POS SUB_POS(1,1), SUB_SIZE(5,1)
+#define INC_POS SUB_POS(6,1), SUB_SIZE(2,1)
+#define DEC_POS SUB_POS(8,1), SUB_SIZE(2,1)
+
+namespace FTDI {
+ void draw_adjuster_value(CommandProcessor& cmd, int16_t x, int16_t y, int16_t w, int16_t h, float value, FSTR_P units, int8_t width, uint8_t precision) {
+ char str[width + precision + 10 + (units ? strlen_P((const char*) units) : 0)];
+ if (isnan(value))
+ strcpy_P(str, PSTR("-"));
+ else
+ dtostrf(value, width, precision, str);
+
+ if (units) {
+ strcat_P(str, PSTR(" "));
+ strcat_P(str, (const char*) units);
+ }
+
+ cmd.tag(0).text(VAL_POS, str);
+ }
+
+ void draw_adjuster(CommandProcessor& cmd, int16_t x, int16_t y, int16_t w, int16_t h, uint8_t tag, float value, FSTR_P units, int8_t width, uint8_t precision, draw_mode_t what) {
+ if (what & BACKGROUND)
+ cmd.tag(0).button(VAL_POS, F(""), FTDI::OPT_FLAT);
+
+ if (what & FOREGROUND) {
+ draw_adjuster_value(cmd, x, y, w, h, value, units, width, precision);
+ cmd.tag(tag ).button(INC_POS, F("-"))
+ .tag(tag+1).button(DEC_POS, F("+"));
+ }
+ }
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/adjuster_widget.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/adjuster_widget.h
new file mode 100644
index 0000000..fa5f8e4
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/adjuster_widget.h
@@ -0,0 +1,40 @@
+/*********************
+ * adjuster_widget.h *
+ *********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2021 - Cocoa Press *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+namespace FTDI {
+ void draw_adjuster_value(
+ CommandProcessor& cmd,
+ int16_t x, int16_t y, int16_t w, int16_t h,
+ float value, FSTR_P units = nullptr,
+ int8_t width = 5, uint8_t precision = 1
+ );
+
+ void draw_adjuster(
+ CommandProcessor& cmd,
+ int16_t x, int16_t y, int16_t w, int16_t h,
+ uint8_t tag,
+ float value, FSTR_P units = nullptr,
+ int8_t width = 5, uint8_t precision = 1,
+ draw_mode_t what = BOTH
+ );
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/arrows.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/arrows.cpp
new file mode 100644
index 0000000..0a45c0d
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/arrows.cpp
@@ -0,0 +1,52 @@
+/**************
+ * arrows.cpp *
+ **************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2021 - SynDaver 3D *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+#define COORD(X,Y) cx + s*(swapXY ? Y : (flipX ? -X : X)), cy + s*(swapXY ? (flipX ? -X : X) : Y)
+
+namespace FTDI {
+
+ void drawArrow(int x, int y, int w, int h, Direction direction) {
+ const bool swapXY = direction == UP || direction == DOWN;
+ const bool flipX = direction == UP || direction == LEFT;
+ const int s = min(w,h);
+ const int cx = (x + w/2)*16;
+ const int cy = (y + h/2)*16;
+
+ CommandProcessor cmd;
+ cmd.cmd(SAVE_CONTEXT())
+ .cmd(LINE_WIDTH(s/2))
+ .cmd(BEGIN(LINES))
+ .cmd(VERTEX2F(COORD( 5, 0)))
+ .cmd(VERTEX2F(COORD( 2,-2)))
+ .cmd(VERTEX2F(COORD( 5, 0)))
+ .cmd(VERTEX2F(COORD( 2, 2)))
+ .cmd(VERTEX2F(COORD( 5, 0)))
+ .cmd(VERTEX2F(COORD(-5, 0)))
+ .cmd(RESTORE_CONTEXT());
+ }
+
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/arrows.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/arrows.h
new file mode 100644
index 0000000..e9592d4
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/arrows.h
@@ -0,0 +1,28 @@
+/************
+ * arrows.h *
+ ************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2021 - SynDaver 3D *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+namespace FTDI {
+ enum Direction {UP, DOWN, LEFT, RIGHT};
+
+ void drawArrow(int x, int y, int w, int h, Direction direction);
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/bitmap_info.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/bitmap_info.h
new file mode 100644
index 0000000..7326070
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/bitmap_info.h
@@ -0,0 +1,49 @@
+/*****************
+ * bitmap_info.h *
+ *****************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#ifndef FORCEDINLINE
+ #define FORCEDINLINE __attribute__((always_inline)) inline
+#endif
+
+namespace FTDI {
+ // The following functions *must* be inlined since we are relying on the compiler to do
+ // substitution of the constants from the data structure rather than actually storing
+ // it in PROGMEM (which would fail, since we are not using pgm_read to read them).
+ // Plus, by inlining, all the equations are evaluated at compile-time as everything
+ // should be a constant.
+
+ typedef struct {
+ const uint8_t format;
+ const uint16_t linestride;
+ const uint8_t filter;
+ const uint8_t wrapx;
+ const uint8_t wrapy;
+ const uint32_t RAMG_offset;
+ const uint16_t width;
+ const uint16_t height;
+ } bitmap_info_t;
+
+ FORCEDINLINE uint32_t BITMAP_SOURCE (const bitmap_info_t& info) {return BITMAP_SOURCE (ftdi_memory_map::RAM_G + info.RAMG_offset);};
+ FORCEDINLINE uint32_t BITMAP_LAYOUT (const bitmap_info_t& info) {return BITMAP_LAYOUT (info.format, info.linestride, info.height);};
+ FORCEDINLINE uint32_t BITMAP_SIZE (const bitmap_info_t& info) {return BITMAP_SIZE (info.filter, info.wrapx, info.wrapy, info.width, info.height);}
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.cpp
new file mode 100644
index 0000000..32cc37d
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.cpp
@@ -0,0 +1,108 @@
+/*************************
+ * circular_progress.cpp *
+ *************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+/* This function draws a circular progress "ring" */
+namespace FTDI {
+ void draw_circular_progress(CommandProcessor& cmd, int x, int y, int w, int h, float percent, char *text, uint32_t bgcolor, uint32_t fgcolor) {
+ const float rim = 0.3;
+ const float a = percent/100.0*2.0*PI;
+ const float a1 = min(PI/2, a);
+ const float a2 = min(PI/2, a-a1);
+ const float a3 = min(PI/2, a-a1-a2);
+ const float a4 = min(PI/2, a-a1-a2-a3);
+
+ const int ro = min(w,h) * 8;
+ const int rr = ro * rim;
+ const int cx = x * 16 + w * 8;
+ const int cy = y * 16 + h * 8;
+
+ // Load a rim shape into stencil buffer
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(TAG_MASK(0));
+ cmd.cmd(CLEAR(0,1,0));
+ cmd.cmd(COLOR_MASK(0,0,0,0));
+ cmd.cmd(STENCIL_OP(STENCIL_OP_KEEP, STENCIL_OP_INVERT));
+ cmd.cmd(STENCIL_FUNC(STENCIL_FUNC_ALWAYS, 255, 255));
+ cmd.cmd(BEGIN(POINTS));
+ cmd.cmd(POINT_SIZE(ro));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(POINT_SIZE(ro - rr));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(RESTORE_CONTEXT());
+
+ // Mask further drawing by stencil buffer
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(STENCIL_FUNC(STENCIL_FUNC_NOTEQUAL, 0, 255));
+
+ // Fill the background
+ cmd.cmd(COLOR_RGB(bgcolor));
+ cmd.cmd(BEGIN(POINTS));
+ cmd.cmd(POINT_SIZE(ro));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(COLOR_RGB(fgcolor));
+
+ // Paint upper-right quadrant
+ cmd.cmd(BEGIN(EDGE_STRIP_A));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(VERTEX2F(cx + ro*sin(a1) + 16,cy - ro*cos(a1) + 8));
+
+ // Paint lower-right quadrant
+ if (a > PI/2) {
+ cmd.cmd(BEGIN(EDGE_STRIP_R));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(VERTEX2F(cx + ro*cos(a2),cy + ro*sin(a2) + 16));
+ }
+
+ // Paint lower-left quadrant
+ if (a > PI) {
+ cmd.cmd(BEGIN(EDGE_STRIP_B));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(VERTEX2F(cx - ro*sin(a3) - 8,cy + ro*cos(a3)));
+ }
+
+ // Paint upper-left quadrant
+ if (a > 1.5*PI) {
+ cmd.cmd(BEGIN(EDGE_STRIP_L));
+ cmd.cmd(VERTEX2F(cx, cy));
+ cmd.cmd(VERTEX2F(cx - ro*cos(a4),cy - ro*sin(a4)));
+ }
+ cmd.cmd(RESTORE_CONTEXT());
+
+ // Draw the text
+
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(COLOR_RGB(fgcolor));
+ cmd.text(x,y,w,h,text, OPT_CENTERX | OPT_CENTERY);
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+
+ void draw_circular_progress(CommandProcessor& cmd, int x, int y, int w, int h, float percent, uint32_t bgcolor, uint32_t fgcolor) {
+ char str[5];
+ sprintf(str,"%d\%%",int(percent));
+ draw_circular_progress(cmd, x, y, w, h, percent, str, bgcolor, fgcolor);
+ }
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.h
new file mode 100644
index 0000000..68fc06b
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/circular_progress.h
@@ -0,0 +1,27 @@
+/***********************
+ * circular_progress.h *
+ ***********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+namespace FTDI {
+ void draw_circular_progress(CommandProcessor& cmd, int x, int y, int w, int h, float percent, char *text, uint32_t bgcolor, uint32_t fgcolor);
+ void draw_circular_progress(CommandProcessor& cmd, int x, int y, int w, int h, float percent, uint32_t bgcolor, uint32_t fgcolor);
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp
new file mode 100644
index 0000000..fd9c70f
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp
@@ -0,0 +1,41 @@
+/*************************
+ * command_processor.cpp *
+ *************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+CommandProcessor::btn_style_func_t *CommandProcessor::_btn_style_callback = CommandProcessor::default_button_style_func;
+bool CommandProcessor::is_tracking = false;
+
+uint32_t CommandProcessor::memcrc(uint32_t ptr, uint32_t num) {
+ const uint16_t x = CLCD::mem_read_16(CLCD::REG::CMD_WRITE);
+ memcrc(ptr, num, 0);
+ wait();
+ return CLCD::mem_read_32(CLCD::MAP::RAM_CMD + x + 12);
+}
+
+bool CommandProcessor::wait() {
+ while (is_processing() && !has_fault()) { /* nada */ }
+ return !has_fault();
+}
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h
new file mode 100644
index 0000000..648ed53
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h
@@ -0,0 +1,452 @@
+/***********************
+ * command_processor.h *
+ ***********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+typedef struct {
+ uint32_t bg;
+ uint32_t grad;
+ uint32_t fg;
+ uint32_t rgb;
+} btn_colors;
+
+// Disable TOUCH_UI_FIT_TEXT on a case-by-case basis
+namespace FTDI {
+ constexpr uint16_t OPT_NOFIT = OPT_NOTICKS;
+}
+
+/**************************** Enhanced Command Processor **************************/
+
+/* The CommandProcessor class wraps the CommandFifo with several features to make
+ * defining user interfaces much easier.
+ *
+ * - Implements chaining on all methods
+ * - Automatically adds text to button, toggle, text and keys.
+ * - Constrains all widgets to fit inside a box for ease of layout.
+ * - Font size is specified using a chained modifier.
+ * - Option argument is given the default OPT_3D value.
+ */
+
+class CommandProcessor : public CLCD::CommandFifo {
+ public:
+ static constexpr uint8_t STYLE_DISABLED = 0x80;
+
+ private:
+ static bool default_button_style_func(CommandProcessor &, uint8_t tag, uint8_t & /*style*/, uint16_t &options, bool) {
+ if (tag != 0 && FTDI::EventLoop::get_pressed_tag() == tag) {
+ options = FTDI::OPT_FLAT;
+ }
+ return false;
+ }
+
+ typedef bool btn_style_func_t(CommandProcessor &cmd, uint8_t tag, uint8_t &style, uint16_t &options, bool post);
+
+ static btn_style_func_t *_btn_style_callback;
+ static bool is_tracking;
+ int8_t _font = 26, _tag = 0;
+ uint8_t _style = 0;
+
+ protected:
+ // Returns the canonical thickness of a widget (i.e. the height of a toggle element)
+ uint16_t widget_thickness() {
+ CLCD::FontMetrics fm(_font);
+ return fm.height * 20.0/16;
+ }
+
+ FORCEDINLINE void linear_widget_box(int16_t &x, int16_t &y, int16_t &w, int16_t &h, bool tracker = false) {
+ const uint16_t th = widget_thickness() / 2;
+ if (w > h) {
+ x += tracker ? th * 2.5 : th;
+ y += (h - th) / 2;
+ w -= tracker ? th * 5.0 : th * 2;
+ h = th;
+ }
+ else {
+ x += (w - th) / 2;
+ y += tracker ? th * 2.5 : th;
+ w = th;
+ h -= tracker ? th * 5.0 : th * 2;
+ }
+ }
+
+ FORCEDINLINE uint16_t circular_widget_box(int16_t &x, int16_t &y, int16_t &w, int16_t &h) {
+ const uint16_t r = min(w,h) / 2;
+ x += w / 2;
+ y += h / 2;
+ w = 1;
+ h = 1;
+ return r;
+ }
+
+ public:
+ // Helper method for setting all colors at once
+ inline CommandProcessor& colors(const btn_colors &colors) {
+ cmd(FTDI::COLOR_RGB(colors.rgb))
+ .gradcolor(colors.grad)
+ .fgcolor(colors.fg)
+ .bgcolor(colors.bg);
+ return *this;
+ }
+
+ inline CommandProcessor& bitmap_size(uint8_t filter, uint8_t wrapx, uint8_t wrapy, uint16_t width, uint16_t height) {
+ cmd(FTDI::BITMAP_SIZE(filter, wrapx, wrapy, width, height));
+ #if FTDI_API_LEVEL >= 810
+ if (FTDI::ftdi_chip >= 810)
+ cmd(FTDI::BITMAP_SIZE_H(width >> 9, height >> 9));
+ #endif
+ return *this;
+ }
+
+ inline CommandProcessor& bitmap_layout(uint8_t format, uint16_t linestride, uint16_t height) {
+ cmd(FTDI::BITMAP_LAYOUT(format, linestride, height));
+ #if FTDI_API_LEVEL >= 810
+ if (FTDI::ftdi_chip >= 810)
+ cmd(FTDI::BITMAP_LAYOUT_H(linestride >> 10, height >> 9));
+ #endif
+ return *this;
+ }
+
+ inline CommandProcessor& set_button_style_callback(const btn_style_func_t *func) {
+ _btn_style_callback = func ? func : default_button_style_func;
+ return *this;
+ }
+
+ inline CommandProcessor& tag (uint8_t tag) {_tag = tag; cmd(FTDI::TAG(tag)); return *this;}
+
+ inline CommandProcessor& font (int16_t font) {_font = font; return *this;}
+
+ inline CommandProcessor& enabled (bool enabled=false) {
+ if (enabled)
+ _style &= ~STYLE_DISABLED;
+ else
+ _style |= STYLE_DISABLED;
+ return *this;
+ }
+
+ inline CommandProcessor& style (uint8_t style) {
+ _style = (_style & STYLE_DISABLED) | style;
+ return *this;
+ }
+
+ bool wait();
+ uint32_t memcrc(uint32_t ptr, uint32_t num);
+
+ // Wrap all the CommandFifo routines to allow method chaining
+
+ inline CommandProcessor& cmd (uint32_t cmd32) {CLCD::CommandFifo::cmd(cmd32); return *this;}
+ inline CommandProcessor& cmd (void *data, uint16_t len) {CLCD::CommandFifo::cmd(data, len); return *this;}
+ inline CommandProcessor& execute() {CLCD::CommandFifo::execute(); return *this;}
+
+ inline CommandProcessor& fgcolor (uint32_t rgb) {CLCD::CommandFifo::fgcolor(rgb); return *this;}
+ inline CommandProcessor& bgcolor (uint32_t rgb) {CLCD::CommandFifo::bgcolor(rgb); return *this;}
+ inline CommandProcessor& gradcolor(uint32_t rgb) {CLCD::CommandFifo::gradcolor(rgb); return *this;}
+
+ inline CommandProcessor& snapshot (uint32_t ptr) {CLCD::CommandFifo::snapshot(ptr); return *this;}
+
+ inline CommandProcessor& loadimage(uint32_t ptr, uint32_t options)
+ {CLCD::CommandFifo::loadimage(ptr, options); return *this;}
+ inline CommandProcessor& sketch (int16_t x, int16_t y, uint16_t w, uint16_t h, uint32_t ptr, uint16_t format)
+ {CLCD::CommandFifo::sketch(x, y, w, h, ptr, format); return *this;}
+ inline CommandProcessor& screensaver () {CLCD::CommandFifo::screensaver(); return *this;}
+ #if FTDI_API_LEVEL >= 810
+ inline CommandProcessor& setbase (uint8_t base) {CLCD::CommandFifo::setbase(base); return *this;}
+ #endif
+ inline CommandProcessor& loadidentity () {CLCD::CommandFifo::loadidentity(); return *this;}
+ inline CommandProcessor& scale (int32_t sx, int32_t sy) {CLCD::CommandFifo::scale(sx,sy); return *this;}
+ inline CommandProcessor& rotate (int32_t a) {CLCD::CommandFifo::rotate(a); return *this;}
+ inline CommandProcessor& translate(int32_t tx, int32_t ty) {CLCD::CommandFifo::translate(tx,ty); return *this;}
+ inline CommandProcessor& setmatrix () {CLCD::CommandFifo::setmatrix(); return *this;}
+ inline CommandProcessor& stop () {CLCD::CommandFifo::stop(); return *this;}
+
+ inline CommandProcessor& memzero (uint32_t ptr, uint32_t size)
+ {CLCD::CommandFifo::memzero(ptr, size); return *this;}
+ inline CommandProcessor& memset (uint32_t ptr, uint32_t val, uint32_t size)
+ {CLCD::CommandFifo::memset(ptr, val, size); return *this;}
+ inline CommandProcessor& memcpy (uint32_t src, uint32_t dst, uint32_t size)
+ {CLCD::CommandFifo::memcpy(src, dst, size); return *this;}
+ inline CommandProcessor& memcrc (uint32_t ptr, uint32_t num, uint32_t result)
+ {CLCD::CommandFifo::memcrc(ptr, num, result); return *this;}
+ inline CommandProcessor& memwrite (uint32_t ptr, uint32_t value)
+ {CLCD::CommandFifo::memwrite(ptr, value); return *this;}
+ inline CommandProcessor& inflate (uint32_t ptr)
+ {CLCD::CommandFifo::inflate(ptr); return *this;}
+ inline CommandProcessor& getptr (uint32_t result)
+ {CLCD::CommandFifo::getptr(result); return *this;}
+ inline CommandProcessor& getprops (uint32_t ptr, uint32_t width, uint32_t height)
+ {CLCD::CommandFifo::getprops(ptr, width, height); return *this;}
+
+ #if FTDI_API_LEVEL >= 810
+ inline CommandProcessor& setbitmap (uint32_t ptr, uint16_t fmt, uint16_t w, uint16_t h)
+ {CLCD::CommandFifo::setbitmap(ptr,fmt,w,h); return *this;}
+ inline CommandProcessor& snapshot2 (uint32_t fmt, uint32_t ptr, int16_t x, int16_t y, uint16_t w, uint16_t h)
+ {CLCD::CommandFifo::snapshot2(fmt,ptr,x,y,w,h); return *this;}
+ inline CommandProcessor& mediafifo (uint32_t p, uint32_t s) {CLCD::CommandFifo::mediafifo(p, s); return *this;}
+ inline CommandProcessor& playvideo(uint32_t options) {CLCD::CommandFifo::playvideo(options); return *this;}
+ inline CommandProcessor& romfont(uint8_t font, uint8_t slot) {CLCD::CommandFifo::romfont(font, slot); return *this;}
+ #endif
+
+ inline CommandProcessor& gradient(int16_t x0, int16_t y0, uint32_t rgb0, int16_t x1, int16_t y1, uint32_t rgb1)
+ {CLCD::CommandFifo::gradient(x0,y0,rgb0,x1,y1,rgb1); return *this;}
+
+ inline CommandProcessor& rectangle(int16_t x, int16_t y, int16_t w, int16_t h) {
+ using namespace FTDI;
+ CLCD::CommandFifo::cmd(BEGIN(RECTS));
+ CLCD::CommandFifo::cmd(VERTEX2F( x * 16, y * 16));
+ CLCD::CommandFifo::cmd(VERTEX2F((x + w) * 16, (y + h) * 16));
+ return *this;
+ }
+
+ inline CommandProcessor& border(int16_t x, int16_t y, int16_t w, int16_t h) {
+ using namespace FTDI;
+ CLCD::CommandFifo::cmd(BEGIN(LINES));
+ CLCD::CommandFifo::cmd(VERTEX2F( x * 16, y * 16));
+ CLCD::CommandFifo::cmd(VERTEX2F((x + w) * 16, y * 16));
+ CLCD::CommandFifo::cmd(VERTEX2F((x + w) * 16, y * 16));
+ CLCD::CommandFifo::cmd(VERTEX2F((x + w) * 16, (y + h) * 16));
+ CLCD::CommandFifo::cmd(VERTEX2F((x + w) * 16, (y + h) * 16));
+ CLCD::CommandFifo::cmd(VERTEX2F( x * 16, (y + h) * 16));
+ CLCD::CommandFifo::cmd(VERTEX2F( x * 16, (y + h) * 16));
+ CLCD::CommandFifo::cmd(VERTEX2F( x * 16, y * 16));
+ return *this;
+ }
+
+ template
+ FORCEDINLINE CommandProcessor& toggle(int16_t x, int16_t y, int16_t w, int16_t h, T text, bool state, uint16_t options = FTDI::OPT_3D) {
+ CLCD::FontMetrics fm(_font);
+ const int16_t widget_h = fm.height * 20.0 / 16;
+ // The y coordinate of the toggle is the baseline of the text,
+ // so we must introduce a fudge factor based on the line height to
+ // actually center the control.
+ const int16_t fudge_y = fm.height * 5 / 16;
+ CLCD::CommandFifo::toggle(x + widget_h, y + (h - widget_h) / 2 + fudge_y, w - widget_h, _font, options, state);
+ CLCD::CommandFifo::str(text);
+ return *this;
+ }
+
+ CommandProcessor& toggle2(int16_t x, int16_t y, int16_t w, int16_t h, FSTR_P no, FSTR_P yes, bool state, uint16_t options = FTDI::OPT_3D) {
+ char text[strlen_P(FTOP(no)) + strlen_P(FTOP(yes)) + 2];
+ strcpy_P(text, FTOP(no));
+ strcat(text, "\xFF");
+ strcat_P(text, FTOP(yes));
+ return toggle(x, y, w, h, text, state, options);
+ }
+
+ // Constrained drawing routines. These constrain the widget inside a box for easier layout.
+ // The FORCEDINLINE ensures that the code is inlined so that all the math is done at compile time.
+
+ FORCEDINLINE CommandProcessor& track_linear(int16_t x, int16_t y, int16_t w, int16_t h, int16_t tag) {
+ linear_widget_box(x, y, w, h, true);
+ CLCD::CommandFifo::track(x, y, w, h, tag);
+ is_tracking = true;
+ return *this;
+ }
+
+ FORCEDINLINE CommandProcessor& track_circular(int16_t x, int16_t y, int16_t w, int16_t h, int16_t tag) {
+ circular_widget_box(x,y, w, h);
+ CLCD::CommandFifo::track(x, y, w, h, tag);
+ is_tracking = true;
+ return *this;
+ }
+
+ uint8_t track_tag (uint16_t &value) {
+ if (is_tracking) {
+ if (FTDI::EventLoop::is_touch_held()) {
+ return CLCD::get_tracker(value);
+ }
+ else {
+ CLCD::CommandFifo::track(0, 0, 0, 0, 0);
+ CLCD::CommandFifo::execute();
+ is_tracking = false;
+ }
+ }
+ return 0;
+ }
+
+ FORCEDINLINE CommandProcessor& clock(int16_t x, int16_t y, int16_t w, int16_t h, int16_t hr, int16_t m, int16_t s, int16_t ms, uint16_t options = FTDI::OPT_3D) {
+ const uint16_t r = circular_widget_box(x, y, w, h);
+ CLCD::CommandFifo::clock(x, y, r, options, hr, m, s, ms);
+ return *this;
+ }
+
+ FORCEDINLINE CommandProcessor& gauge(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t major, uint16_t minor, uint16_t val, uint16_t range, uint16_t options = FTDI::OPT_3D) {
+ const uint16_t r = circular_widget_box(x, y, w, h);
+ CLCD::CommandFifo::gauge(x, y, r, options, major, minor, val, range);
+ return *this;
+ }
+
+ FORCEDINLINE CommandProcessor& dial(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t val, uint16_t options = FTDI::OPT_3D) {
+ const uint16_t r = circular_widget_box(x, y, w, h);
+ CLCD::CommandFifo::dial(x, y, r, options, val);
+ return *this;
+ }
+
+ FORCEDINLINE CommandProcessor& slider(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t val, uint16_t range, uint16_t options = FTDI::OPT_3D) {
+ linear_widget_box(x, y, w, h);
+ CLCD::CommandFifo::slider(x, y, w, h, options, val, range);
+ return *this;
+ }
+
+ FORCEDINLINE CommandProcessor& progress(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t val, uint16_t range, uint16_t options = FTDI::OPT_3D) {
+ linear_widget_box(x, y, w, h);
+ CLCD::CommandFifo::progress(x, y, w, h, options, val, range);
+ return *this;
+ }
+
+ FORCEDINLINE CommandProcessor& scrollbar(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t val, uint16_t size, uint16_t range, uint16_t options = 0) {
+ linear_widget_box(x, y, w, h);
+ CLCD::CommandFifo::scrollbar(x, y, w, h, options, val, size, range);
+ return *this;
+ }
+
+ void apply_text_alignment(int16_t &x, int16_t &y, int16_t w, int16_t h, uint16_t options) {
+ using namespace FTDI;
+ x += ((options & OPT_CENTERX) ? w/2 : ((options & OPT_RIGHTX) ? w : 0));
+ y += ((options & OPT_CENTERY) ? h/2 : h);
+ }
+
+ // Reduce font size until text fits the enclosing box.
+ template
+ int8_t apply_fit_text(int16_t w, int16_t h, T text) {
+ using namespace FTDI;
+ int8_t font = _font;
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ const bool is_utf8 = has_utf8_chars(text);
+ #endif
+ for (;font > 26;) {
+ int16_t width, height;
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (is_utf8) {
+ width = get_utf8_text_width(text, font_size_t::from_romfont(font));
+ height = font_size_t::from_romfont(font).get_height();
+ }
+ else
+ #endif
+ {
+ CLCD::FontMetrics fm(font);
+ width = fm.get_text_width(text);
+ height = fm.height;
+ }
+ if (width < w && height < h) break;
+ font--;
+ }
+ return font;
+ }
+
+ CommandProcessor& number(int16_t x, int16_t y, int16_t w, int16_t h, int32_t n, uint16_t options = FTDI::OPT_CENTER) {
+ using namespace FTDI;
+ apply_text_alignment(x, y, w, h, options);
+ CLCD::CommandFifo::number(x, y, _font, options, n);
+ return *this;
+ }
+
+ template
+ uint16_t text_width(T text) {
+ using namespace FTDI;
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (has_utf8_chars(text))
+ return get_utf8_text_width(text, font_size_t::from_romfont(_font));
+ #endif
+ CLCD::FontMetrics fm(_font);
+ return fm.get_text_width(text);
+ }
+
+ template
+ CommandProcessor& text(int16_t x, int16_t y, int16_t w, int16_t h, T text, uint16_t options = FTDI::OPT_CENTER) {
+ using namespace FTDI;
+ apply_text_alignment(x, y, w, h, options);
+ #ifdef TOUCH_UI_FIT_TEXT
+ const int8_t font = (options & OPT_NOFIT) ? _font : apply_fit_text(w, h, text);
+ #else
+ const int8_t font = _font;
+ #endif
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (has_utf8_chars(text))
+ draw_utf8_text(*this, x, y, text, font_size_t::from_romfont(font), options);
+ else
+ #endif
+ {
+ CLCD::CommandFifo::text(x, y, font, options);
+ CLCD::CommandFifo::str(text);
+ }
+ return *this;
+ }
+
+ FORCEDINLINE CommandProcessor& icon(int16_t x, int16_t y, int16_t w, int16_t h, const FTDI::bitmap_info_t& info, const float scale = 1) {
+ using namespace FTDI;
+ cmd(BEGIN(BITMAPS));
+ if (scale != 1) {
+ cmd(BITMAP_TRANSFORM_A(uint32_t(float(256)/scale)));
+ cmd(BITMAP_TRANSFORM_E(uint32_t(float(256)/scale)));
+ }
+ cmd(BITMAP_SIZE(info.filter, info.wrapx, info.wrapy, info.width*scale, info.height*scale));
+ cmd(VERTEX2F((x + w/2 - info.width*scale/2)*16, (y + h/2 - info.height*scale/2)*16));
+ if (scale != 1) {
+ cmd(BITMAP_TRANSFORM_A(256));
+ cmd(BITMAP_TRANSFORM_E(256));
+ }
+ return *this;
+ }
+
+ template
+ CommandProcessor& button(int16_t x, int16_t y, int16_t w, int16_t h, T text, uint16_t options = FTDI::OPT_3D) {
+ using namespace FTDI;
+ bool styleModified = false;
+ if (_btn_style_callback) styleModified = _btn_style_callback(*this, _tag, _style, options, false);
+ #ifdef TOUCH_UI_FIT_TEXT
+ const int8_t font = (options & OPT_NOFIT) ? _font : apply_fit_text(w, h, text);
+ #else
+ const int8_t font = _font;
+ #endif
+ CLCD::CommandFifo::button(x, y, w, h, font, options);
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (has_utf8_chars(text)) {
+ CLCD::CommandFifo::str(F(""));
+ apply_text_alignment(x, y, w, h, OPT_CENTER);
+ if (!(options & FTDI::OPT_FLAT)) {
+ // Reproduce the black "shadow" the FTDI adds to the button label
+ CLCD::CommandFifo::cmd(SAVE_CONTEXT());
+ CLCD::CommandFifo::cmd(COLOR_RGB(0x00000));
+ draw_utf8_text(*this, x-1, y-1, text, font_size_t::from_romfont(font), OPT_CENTER);
+ CLCD::CommandFifo::cmd(RESTORE_CONTEXT());
+ }
+ // Draw the button label
+ draw_utf8_text(*this, x, y, text, font_size_t::from_romfont(font), OPT_CENTER);
+ }
+ else
+ #endif
+ CLCD::CommandFifo::str(text);
+ if (_btn_style_callback && styleModified) _btn_style_callback(*this, _tag, _style, options, true);
+ return *this;
+ }
+
+ template
+ CommandProcessor& keys(int16_t x, int16_t y, int16_t w, int16_t h, T keys, uint16_t options = FTDI::OPT_3D) {
+ CLCD::CommandFifo::keys(x, y, w, h, _font, options);
+ CLCD::CommandFifo::str(keys);
+ return *this;
+ }
+
+ FORCEDINLINE CommandProcessor& spinner(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t style = 0, uint16_t scale = 0) {
+ circular_widget_box(x, y, w, h);
+ CLCD::CommandFifo::spinner(x, y, style, scale);
+ return *this;
+ }
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp
new file mode 100644
index 0000000..f947a35
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp
@@ -0,0 +1,174 @@
+/****************
+ * dl_cache.cpp *
+ ****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+/* The Display List Cache mechanism stores the display list corresponding
+ * to a menu into RAM_G so that on subsequent calls drawing the menu does
+ * not require as much SPI traffic.
+ *
+ * Layout of Cache memory:
+ *
+ * The cache memory begins with a table at
+ * DL_CACHE_START: each table entry contains
+ * an address, size and used bytes for a cached
+ * DL slot.
+ *
+ * Immediately following the table is the
+ * DL_FREE_ADDR, which points to free cache
+ * space; following this is occupied DL space,
+ * and after that free space that is yet to
+ * be used.
+ *
+ * location data sizeof
+ *
+ * DL_CACHE_START slot0_addr 4
+ * slot0_size 4
+ * slot0_used 4
+ * slot1_addr 4
+ * slot1_size 4
+ * slot1_used 4
+ * ...
+ * slotN_addr 4
+ * slotN_size 4
+ * slotN_used 4
+ * DL_FREE_ADDR dl_free_ptr 4
+ * cached data
+ * ...
+ * dl_free_ptr empty space
+ * ...
+ */
+
+#define DL_CACHE_START MAP::RAM_G_SIZE - 0xFFFF
+#define DL_FREE_ADDR DL_CACHE_START + DL_CACHE_SLOTS * 12
+
+using namespace FTDI;
+
+// The init function ensures all cache locations are marked as empty
+
+void DLCache::init() {
+ CLCD::mem_write_32(DL_FREE_ADDR, DL_FREE_ADDR + 4);
+ for (uint8_t slot = 0; slot < DL_CACHE_SLOTS; slot++)
+ save_slot(slot, 0, 0, 0);
+}
+
+bool DLCache::has_data() {
+ return dl_slot_size != 0;
+}
+
+bool DLCache::wait_until_idle() {
+ const unsigned long startTime = millis();
+ do {
+ if ((millis() - startTime) > 250) {
+ SERIAL_ECHO_MSG("Timeout on DL_Cache::Wait_Until_Idle()");
+ CLCD::CommandFifo::reset();
+ return false;
+ }
+ #ifdef __MARLIN_FIRMWARE__
+ ExtUI::yield();
+ #endif
+ } while (CLCD::CommandFifo::is_processing());
+ return true;
+}
+
+/* This caches the current display list in RAMG so
+ * that it can be appended later. The memory is
+ * dynamically allocated following DL_FREE_ADDR.
+ *
+ * If min_bytes is provided, then that many bytes
+ * will be reserved so that the cache may be re-written
+ * later with potentially a bigger DL.
+ */
+
+bool DLCache::store(uint32_t min_bytes /* = 0*/) {
+ CLCD::CommandFifo cmd;
+
+ // Execute any commands already in the FIFO
+ cmd.execute();
+ if (!wait_until_idle())
+ return false;
+
+ // Figure out how long the display list is
+ const uint32_t dl_size = CLCD::dl_size();
+
+ if (dl_slot_addr == 0) {
+ // If we are allocating new space...
+ dl_slot_addr = CLCD::mem_read_32(DL_FREE_ADDR);
+ dl_slot_size = max(dl_size, min_bytes);
+
+ const uint32_t free_space = MAP::RAM_G_SIZE - dl_slot_addr;
+ if (dl_slot_size <= free_space) {
+ CLCD::mem_write_32(DL_FREE_ADDR, dl_slot_addr + dl_slot_size);
+ }
+ else {
+ dl_slot_addr = 0;
+ dl_slot_size = 0;
+ dl_slot_used = 0;
+ }
+ }
+
+ if (dl_size > dl_slot_size) {
+ // Not enough memory to cache the display list.
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Not enough space in GRAM to cache display list, free space: ", dl_slot_size, " Required: ", dl_size);
+ #endif
+ dl_slot_used = 0;
+ save_slot();
+ return false;
+ }
+ else {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Saving DL to RAMG cache, bytes: ", dl_slot_used, " Free space: ", dl_slot_size);
+ #endif
+ dl_slot_used = dl_size;
+ save_slot();
+ cmd.memcpy(dl_slot_addr, MAP::RAM_DL, dl_slot_used);
+ cmd.execute();
+ return true;
+ }
+}
+
+void DLCache::save_slot(uint8_t indx, uint32_t addr, uint16_t size, uint16_t used) {
+ CLCD::mem_write_32(DL_CACHE_START + indx * 12 + 0, addr);
+ CLCD::mem_write_32(DL_CACHE_START + indx * 12 + 4, size);
+ CLCD::mem_write_32(DL_CACHE_START + indx * 12 + 8, used);
+}
+
+void DLCache::load_slot(uint8_t indx, uint32_t &addr, uint16_t &size, uint16_t &used) {
+ addr = CLCD::mem_read_32(DL_CACHE_START + indx * 12 + 0);
+ size = CLCD::mem_read_32(DL_CACHE_START + indx * 12 + 4);
+ used = CLCD::mem_read_32(DL_CACHE_START + indx * 12 + 8);
+}
+
+void DLCache::append() {
+ CLCD::CommandFifo cmd;
+ cmd.append(dl_slot_addr, dl_slot_used);
+ #if ENABLED(TOUCH_UI_DEBUG)
+ cmd.execute();
+ wait_until_idle();
+ SERIAL_ECHO_MSG("Appending to DL from RAMG cache, bytes: ", dl_slot_used, " REG_CMD_DL: ", CLCD::mem_read_32(REG::CMD_DL));
+ #endif
+}
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h
new file mode 100644
index 0000000..73b4b0b
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h
@@ -0,0 +1,70 @@
+/**************
+ * dl_cache.h *
+ **************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/******************* DISPLAY LIST CACHE MANAGEMENT ************************/
+/* The Display List Cache mechanism stores the display list corresponding
+ * to a menu into RAM_G so that on subsequent calls drawing the menu does
+ * not require as much SPI traffic. Dynamic content, such as indicators,
+ * should not be cached.
+ *
+ * The DLCache can be used like so:
+ *
+ * DLCache dlcache(UNIQUE_ID);
+ *
+ * if (dlcache.hasData())
+ * dlcache.append();
+ * else
+ * dlcache.store(); // Add stuff to the DL
+ */
+class DLCache {
+ private:
+ typedef FTDI::ftdi_registers REG;
+ typedef FTDI::ftdi_memory_map MAP;
+
+ uint8_t dl_slot_indx;
+ uint32_t dl_slot_addr;
+ uint16_t dl_slot_size;
+ uint16_t dl_slot_used;
+
+ void load_slot() {load_slot(dl_slot_indx, dl_slot_addr, dl_slot_size, dl_slot_used);}
+ void save_slot() {save_slot(dl_slot_indx, dl_slot_addr, dl_slot_size, dl_slot_used);}
+
+ static void load_slot(uint8_t indx, uint32_t &addr, uint16_t &size, uint16_t &used);
+ static void save_slot(uint8_t indx, uint32_t addr, uint16_t size, uint16_t used);
+
+ bool wait_until_idle();
+
+ public:
+ static void init();
+
+ DLCache(uint8_t slot) {
+ dl_slot_indx = slot;
+ load_slot();
+ }
+
+ bool has_data();
+ bool store(uint32_t min_bytes = 0);
+ void append();
+};
+
+#define DL_CACHE_SLOTS 250
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp
new file mode 100644
index 0000000..7fccb30
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp
@@ -0,0 +1,226 @@
+/******************
+ * event_loop.cpp *
+ ******************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+using namespace FTDI;
+
+enum {
+ UNPRESSED = 0x00
+};
+
+tiny_timer_t touch_timer;
+UIData::flags_t UIData::flags;
+uint8_t pressed_tag = UNPRESSED;
+
+uint8_t UIData::get_persistent_data_mask() {
+ // A bit mask for flags that should be stored to the EEPROM.
+ // Others are considered temporarily values that need not be
+ // saved.
+ constexpr flags_t persistent_flags = {
+ bits: {
+ touch_start_sound: true,
+ touch_end_sound: true,
+ touch_repeat_sound: true,
+ show_animations: true
+ }
+ };
+ return persistent_flags.value;
+}
+
+void UIData::reset_persistent_data() {
+ // Default values for persistent data
+ constexpr flags_t default_flags = {
+ bits: {
+ touch_start_sound: true,
+ touch_end_sound: true,
+ touch_repeat_sound: true,
+ show_animations: true,
+ touch_debouncing: false,
+ ignore_unpress: false
+ }
+ };
+ flags.value = default_flags.value;
+}
+
+uint8_t UIData::get_persistent_data() {
+ return flags.value & get_persistent_data_mask();
+}
+
+void UIData::set_persistent_data(uint8_t value) {
+ flags.value = value & get_persistent_data_mask();
+}
+
+
+void UIData::enable_touch_sounds(bool enabled) {
+ UIData::flags.bits.touch_start_sound = enabled;
+ UIData::flags.bits.touch_end_sound = enabled;
+ UIData::flags.bits.touch_repeat_sound = enabled;
+}
+
+bool UIData::touch_sounds_enabled() {
+ return UIData::flags.bits.touch_start_sound || UIData::flags.bits.touch_end_sound || UIData::flags.bits.touch_repeat_sound;
+}
+
+void UIData::enable_animations(bool enabled) {
+ UIData::flags.bits.show_animations = enabled;
+}
+
+bool UIData::animations_enabled() {
+ return UIData::flags.bits.show_animations;
+}
+
+namespace FTDI {
+ uint8_t EventLoop::get_pressed_tag() {
+ return pressed_tag;
+ }
+
+ bool EventLoop::is_touch_held() {
+ return pressed_tag != 0;
+ }
+
+ /**
+ * process_events(): Process events from the touch panel.
+ *
+ * This function consists of a state machine that accomplishes the following:
+ *
+ * - Reads the tag register from the touch panel
+ * - Dispatches onTouchStart and onTouchEnd events to the active screen.
+ * - Handles auto-repetition by sending onTouchHeld to the active screen periodically.
+ * - Plays touch feedback "click" sounds when appropriate.
+ * - Performs debouncing to suppress spurious touch events.
+ */
+ void EventLoop::process_events() {
+ // If the LCD is processing commands, don't check
+ // for tags since they may be changing and could
+ // cause spurious events.
+ if (!touch_timer.elapsed(TOUCH_UPDATE_INTERVAL) || CLCD::CommandFifo::is_processing()) {
+ return;
+ }
+
+ const uint8_t tag = CLCD::get_tag();
+
+ switch (pressed_tag) {
+ case UNPRESSED:
+ if (tag != 0) {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Touch start: ", tag);
+ #endif
+
+ pressed_tag = tag;
+ current_screen.onRefresh();
+
+ // When the user taps on a button, activate the onTouchStart handler
+ const uint8_t lastScreen = current_screen.getScreen();
+
+ if (current_screen.onTouchStart(tag)) {
+ touch_timer.start();
+ if (UIData::flags.bits.touch_start_sound) sound.play(press_sound);
+ }
+
+ // In the case in which a touch event triggered a new screen to be
+ // drawn, we don't issue a touchEnd since it would be sent to the
+ // wrong screen.
+ UIData::flags.bits.ignore_unpress = (lastScreen != current_screen.getScreen());
+ }
+ else {
+ touch_timer.start();
+ }
+ break;
+ default: // PRESSED
+ if (!UIData::flags.bits.touch_debouncing) {
+ if (tag == pressed_tag) {
+ // The user is holding down a button.
+ if (touch_timer.elapsed(1000 / TOUCH_REPEATS_PER_SECOND)) {
+ if (current_screen.onTouchHeld(tag)) {
+ current_screen.onRefresh();
+ if (UIData::flags.bits.touch_repeat_sound) sound.play(repeat_sound);
+ }
+ touch_timer.start();
+ }
+ }
+ else if (tag == 0) {
+ touch_timer.start();
+ UIData::flags.bits.touch_debouncing = true;
+ }
+ }
+
+ else {
+ // Debouncing...
+
+ if (tag == pressed_tag) {
+ // If while debouncing, we detect a press, then cancel debouncing.
+ UIData::flags.bits.touch_debouncing = false;
+ }
+
+ else if (touch_timer.elapsed(DEBOUNCE_PERIOD)) {
+ UIData::flags.bits.touch_debouncing = false;
+
+ if (UIData::flags.bits.ignore_unpress) {
+ UIData::flags.bits.ignore_unpress = false;
+ pressed_tag = UNPRESSED;
+ break;
+ }
+
+ if (UIData::flags.bits.touch_end_sound) sound.play(unpress_sound);
+
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Touch end: ", pressed_tag);
+ #endif
+
+ const uint8_t saved_pressed_tag = pressed_tag;
+ pressed_tag = UNPRESSED;
+ current_screen.onTouchEnd(saved_pressed_tag);
+ current_screen.onRefresh();
+ }
+ }
+ break;
+ } // switch (pressed_tag)
+
+ } // processEvents()
+
+ void EventLoop::setup() {
+ CLCD::init();
+ DLCache::init();
+ UIData::reset_persistent_data();
+ current_screen.start();
+ }
+
+ void EventLoop::loop() {
+ sound.onIdle();
+
+ /**
+ * Guard against re-entry of UI methods, which can
+ * crash. Re-entry can happen because some functions
+ * (e.g. planner.synchronize) call idle().
+ */
+ if (!UIData::flags.bits.prevent_reentry) {
+ UIData::flags.bits.prevent_reentry = true;
+ current_screen.onIdle();
+ process_events();
+ UIData::flags.bits.prevent_reentry = false;
+ }
+ }
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.h
new file mode 100644
index 0000000..c5f0829
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.h
@@ -0,0 +1,74 @@
+/****************
+ * event_loop.h *
+ ****************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#define STATUS_UPDATE_INTERVAL 1000
+#define TOUCH_UPDATE_INTERVAL 50
+#define TOUCH_REPEATS_PER_SECOND 4
+#define DEBOUNCE_PERIOD 150
+
+class UIData {
+ private:
+ typedef union {
+ struct {
+ uint8_t touch_start_sound : 1;
+ uint8_t touch_end_sound : 1;
+ uint8_t touch_repeat_sound : 1;
+ uint8_t show_animations : 1;
+ uint8_t touch_debouncing : 1;
+ uint8_t ignore_unpress : 1;
+ uint8_t prevent_reentry : 1;
+ } bits;
+ uint8_t value;
+ } flags_t;
+
+ public:
+ static flags_t flags;
+
+ static uint8_t get_persistent_data_mask();
+ static uint8_t get_persistent_data();
+ static void set_persistent_data(uint8_t value);
+ static void reset_persistent_data();
+
+ static void enable_touch_sounds(bool enabled);
+ static bool touch_sounds_enabled();
+ static void enable_animations(bool enabled);
+ static bool animations_enabled();
+};
+
+namespace FTDI {
+ class EventLoop {
+ private:
+ static constexpr FTDI::effect_t press_sound = FTDI::CHACK;
+ static constexpr FTDI::effect_t repeat_sound = FTDI::CHACK;
+ static constexpr FTDI::effect_t unpress_sound = FTDI::POP;
+ static void process_events();
+
+ public:
+ static void setup();
+ static void loop();
+
+ static uint8_t get_pressed_tag();
+ static bool is_touch_held();
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h
new file mode 100644
index 0000000..e99c798
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h
@@ -0,0 +1,56 @@
+/*******************
+ * ftdi_extended.h *
+ *******************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2019 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 201( - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#include "../compat.h"
+#include "../basic/ftdi_basic.h"
+
+#ifndef __MARLIN_FIRMWARE__
+ #define FTDI_EXTENDED
+#endif
+
+#if ENABLED(FTDI_EXTENDED)
+ #include "unicode/font_size_t.h"
+ #include "unicode/unicode.h"
+ #include "unicode/standard_char_set.h"
+ #include "unicode/western_char_set.h"
+ #include "unicode/cyrillic_char_set.h"
+ #include "unicode/font_bitmaps.h"
+ #include "rgb_t.h"
+ #include "bitmap_info.h"
+ #include "tiny_timer.h"
+ #include "grid_layout.h"
+ #include "dl_cache.h"
+ #include "event_loop.h"
+ #include "command_processor.h"
+ #include "screen_types.h"
+ #include "sound_player.h"
+ #include "sound_list.h"
+ #include "polygon.h"
+ #include "poly_ui.h"
+ #include "arrows.h"
+ #include "text_box.h"
+ #include "text_ellipsis.h"
+ #include "adjuster_widget.h"
+ #include "circular_progress.h"
+#endif
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h
new file mode 100644
index 0000000..813f4f0
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h
@@ -0,0 +1,123 @@
+/*****************
+ * grid_layout.h *
+ *****************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/* The grid layout macros allow buttons to be arranged on a grid so
+ * that their locations become independent of the display size. The
+ * layout model is similar to that of HTML TABLEs.
+ *
+ * These macros are meant to be evaluated into constants at compile
+ * time, so resolution independence can be as efficient as using
+ * hard-coded coordinates.
+ */
+
+// Margin defines the margin (in pixels) on each side of a button in
+// the layout
+
+#ifdef TOUCH_UI_800x480
+ #define MARGIN_L 5
+ #define MARGIN_R 5
+ #define MARGIN_T 5
+ #define MARGIN_B 5
+ #define MARGIN_DEFAULT 5
+#else
+ #define MARGIN_L 3
+ #define MARGIN_R 3
+ #define MARGIN_T 3
+ #define MARGIN_B 3
+ #define MARGIN_DEFAULT 3
+#endif
+
+// The EDGE variables adds some space on the edges of the display
+
+#define EDGE_T 0
+#define EDGE_B 0
+#define EDGE_L 0
+#define EDGE_R 0
+
+// _GRID_X and _GRID_Y computes the positions of the divisions on
+// the layout grid.
+#define _GRID_X(x) ((x)*(FTDI::display_width-EDGE_R-EDGE_L)/GRID_COLS+EDGE_L)
+#define _GRID_Y(y) ((y)*(FTDI::display_height-EDGE_B-EDGE_T)/GRID_ROWS+EDGE_T)
+
+// BOX_X, BOX_Y, BOX_W and BOX_X returns the top-left and width
+// and height of position on the grid.
+
+#define BOX_X(x) (_GRID_X((x)-1))
+#define BOX_Y(y) (_GRID_Y((y)-1))
+#define BOX_W(w) (_GRID_X(w) - _GRID_X(0))
+#define BOX_H(h) (_GRID_Y(h) - _GRID_Y(0))
+
+// BTN_X, BTN_Y, BTN_W and BTN_X returns the top-left and width
+// and height of a button, taking into account the button margins.
+
+#define BTN_X(x) (BOX_X(x) + MARGIN_L)
+#define BTN_Y(y) (BOX_Y(y) + MARGIN_T)
+#define BTN_W(w) (BOX_W(w) - MARGIN_L - MARGIN_R)
+#define BTN_H(h) (BOX_H(h) - MARGIN_T - MARGIN_B)
+
+// Abbreviations for common phrases, to allow a box or button
+// to be defined in one line of source.
+#define BTN_POS(x,y) BTN_X(x), BTN_Y(y)
+#define BTN_SIZE(w,h) BTN_W(w), BTN_H(h)
+#define BOX_POS(x,y) BOX_X(x), BOX_Y(y)
+#define BOX_SIZE(w,h) BOX_W(w), BOX_H(h)
+
+// Draw a reference grid for ease of spacing out widgets.
+#define DRAW_LAYOUT_GRID \
+ { \
+ cmd.cmd(LINE_WIDTH(4)); \
+ for (int i = 1; i <= GRID_COLS; i++) { \
+ cmd.cmd(BEGIN(LINES)); \
+ cmd.cmd(VERTEX2F(_GRID_X(i) *16, 0 *16)); \
+ cmd.cmd(VERTEX2F(_GRID_X(i) *16, FTDI::display_height *16)); \
+ } \
+ for (int i = 1; i < GRID_ROWS; i++) { \
+ cmd.cmd(BEGIN(LINES)); \
+ cmd.cmd(VERTEX2F(0 *16, _GRID_Y(i) *16)); \
+ cmd.cmd(VERTEX2F(FTDI::display_width *16, _GRID_Y(i) *16)); \
+ } \
+ cmd.cmd(LINE_WIDTH(16)); \
+ }
+
+// Routines for subdividing a grid within a box (x,y,w,h)
+
+#define SUB_GRID_W(W) ((W)*w/SUB_COLS)
+#define SUB_GRID_H(H) ((H)*h/SUB_ROWS)
+#define SUB_GRID_X(X) (SUB_GRID_W((X)-1) + x)
+#define SUB_GRID_Y(Y) (SUB_GRID_H((Y)-1) + y)
+#define SUB_X(X) (SUB_GRID_X(X) + MARGIN_L)
+#define SUB_Y(Y) (SUB_GRID_Y(Y) + MARGIN_T)
+#define SUB_W(W) (SUB_GRID_W(W) - MARGIN_L - MARGIN_R)
+#define SUB_H(H) (SUB_GRID_H(H) - MARGIN_T - MARGIN_B)
+#define SUB_POS(X,Y) SUB_X(X), SUB_Y(Y)
+#define SUB_SIZE(W,H) SUB_W(W), SUB_H(H)
+
+namespace FTDI {
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ constexpr uint16_t display_width = Vsize;
+ constexpr uint16_t display_height = Hsize;
+ #else
+ constexpr uint16_t display_width = Hsize;
+ constexpr uint16_t display_height = Vsize;
+ #endif
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/poly_ui.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/poly_ui.h
new file mode 100644
index 0000000..809e729
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/poly_ui.h
@@ -0,0 +1,408 @@
+/*************
+ * poly_ui.h *
+ *************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * The PolyReader class iterates over an array of (x,y) pairs.
+ * For supporting polygons with holes an end-of-loop marker may
+ * be embedded into the data stream:
+ *
+ * const PROGMEM uint16_t data[] = {
+ * x, y, x, y, ..., eol,
+ * ...
+ * x, y, x, y, ..., eol
+ * }
+ *
+ * The PolyReader object can be used to iterate over the points.
+ *
+ * PolyReader r(data, N_ELEMENTS(data));
+ *
+ * for (r.start();r.has_more(); r.next()) {
+ * uint16_t x = r.x;
+ * uint16_t y = r.y;
+ *
+ * // Do something with the point
+ * ...
+ *
+ * // Do something else if this point
+ * // closes a loop.
+ * if (r.end_of_loop()) {
+ * ...
+ * }
+ * }
+ */
+
+class PolyReader {
+ public:
+ typedef uint16_t type_t;
+
+ private:
+ static constexpr type_t eol = 0xFFFF;
+
+ const type_t *p, *top, *end;
+ type_t start_x, start_y;
+
+ void close_loop() {
+ x = start_x;
+ y = start_y;
+ start_x = eol;
+ start_y = eol;
+ }
+
+ public:
+ type_t x, y;
+
+ // Begin reading a polygon data structure
+ PolyReader(const uint16_t data[], const size_t n_elements) : top(data), end(data + n_elements) {
+ start();
+ }
+
+ void start() {
+ p = top;
+ start_x = eol;
+ next();
+ }
+
+ // Reads the next point in the polygon data structure
+ void next() {
+ if (!p) return;
+
+ if (p == end) {
+ if (start_x != eol)
+ close_loop();
+ else
+ p = nullptr;
+ }
+ else {
+ x = pgm_read_word_far(p++);
+ if (x == eol)
+ close_loop();
+ else {
+ y = pgm_read_word_far(p++);
+ if (start_x == eol) {
+ start_x = x;
+ start_y = y;
+ }
+ }
+ }
+ }
+
+ bool has_more() { return p != nullptr; }
+ bool end_of_loop() { return start_x == eol; }
+};
+
+/**
+ * The TransformedPolyReader class works like the PolyReader,
+ * but the (x,y) input is assumed to be normalized onto a
+ * unit square and then mapped to the full 16-bits, i.e.
+ * (0.0,1.0) => (0x0000,0xFFFE). This class will scale the
+ * data to fit the entire display, a bounding box, or apply
+ * some arbitrary affine transform.
+ *
+ * This class is suitable for reading data from "svg2cpp.py"
+ */
+class TransformedPolyReader : public PolyReader {
+ private:
+ /**
+ * Fixed point type for fast transformations, supports
+ * values from 0 to 1024, with 1/32 precision.
+ */
+ static constexpr uint8_t fract_bits = 5;
+ typedef int16_t fix_t;
+ fix_t makefix(float f) { return f * (1 << fract_bits); }
+
+ // First two rows of 3x3 transformation matrix
+ fix_t a, b, c;
+ fix_t d, e, f;
+
+ void transform() {
+ /**
+ * Values from PolyReader vary from 0 to FFFE.
+ * As an approximation to dividing by FFFE,
+ * we perform a bit shift right by 16.
+ */
+ const int32_t px = PolyReader::x;
+ const int32_t py = PolyReader::y;
+ const int32_t round = 1 << (fract_bits-1);
+ x = (((((a * px) + (b * py)) >> 16) + c) + round) >> fract_bits;
+ y = (((((d * px) + (e * py)) >> 16) + f) + round) >> fract_bits;
+ }
+
+ void set_transform(
+ fix_t A, fix_t B, fix_t C,
+ fix_t D, fix_t E, fix_t F
+ ) {
+ a = A; b = B; c = C;
+ d = D; e = E; f = F;
+ }
+
+ public:
+ typedef int16_t type_t;
+
+ type_t x, y;
+
+ TransformedPolyReader(const uint16_t data[], const size_t n) : PolyReader(data, n) {
+ scale_to_fit();
+ transform();
+ }
+
+ // Set an arbitrary affine transform
+ void set_transform(
+ float A, float B, float C,
+ float D, float E, float F
+ ) {
+ set_transform(
+ makefix(A), makefix(B), makefix(C),
+ makefix(D), makefix(E), makefix(F)
+ );
+ }
+
+ // Scale the data to fit a specified bounding box
+ void scale_to_fit(type_t x_min, type_t y_min, type_t x_max, type_t y_max) {
+ fix_t sx = makefix(x_max - x_min);
+ fix_t sy = makefix(y_max - y_min);
+ fix_t tx = makefix(x_min);
+ fix_t ty = makefix(y_min);
+ set_transform(
+ sx, 0, tx,
+ 0, sy, ty
+ );
+ }
+
+ // Scale to fit the entire display (default)
+ void scale_to_fit() {
+ scale_to_fit(0, 0, FTDI::display_width, FTDI::display_height);
+ }
+
+ void next() {
+ PolyReader::next();
+ transform();
+ }
+};
+
+/**
+ * The DeduplicatedPolyReader wraps around another PolyReader
+ * class to remove repeated points from the data. This could
+ * happen when scaling down using TransformedPolyReader, for
+ * example.
+ */
+template
+class DeduplicatedPolyReader : public POLY_READER {
+ private:
+ typename POLY_READER::type_t last_x, last_y;
+
+ static constexpr typename POLY_READER::type_t eol = 0xFFFF;
+
+ public:
+ DeduplicatedPolyReader(const uint16_t data[], const size_t n) : POLY_READER(data, n) {
+ last_x = POLY_READER::x;
+ last_y = POLY_READER::y;
+ }
+
+ void next() {
+ do {
+ if (!POLY_READER::has_more()) return;
+ POLY_READER::next();
+ } while (POLY_READER::x == last_x && POLY_READER::y == last_y && !POLY_READER::end_of_loop());
+ if (POLY_READER::end_of_loop()) {
+ last_x = last_y = eol;
+ }
+ else {
+ last_x = POLY_READER::x;
+ last_y = POLY_READER::y;
+ }
+ }
+};
+
+/**
+ * The helper class allows you to build an interface based on arbitrary
+ * shapes.
+ */
+template>
+class GenericPolyUI {
+ protected:
+ CommandProcessor &cmd;
+ draw_mode_t mode;
+
+ private:
+ // Attributes used to paint buttons
+
+ uint32_t btn_fill_color = 0x000000;
+ uint32_t btn_shadow_color = 0xF3E0E0;
+ uint8_t btn_shadow_depth = 5;
+ uint32_t btn_stroke_color = 0x000000;
+ uint8_t btn_stroke_width = 28;
+
+ public:
+ enum ButtonStyle : uint8_t {
+ FILL = 1,
+ STROKE = 2,
+ SHADOW = 4,
+ REGULAR = 7
+ };
+
+ typedef POLY_READER poly_reader_t;
+
+ GenericPolyUI(CommandProcessor &c, draw_mode_t what = BOTH) : cmd(c), mode(what) {}
+
+ // Fills a polygon with the current COLOR_RGB
+ void fill(poly_reader_t r, bool clip = true) {
+ using namespace FTDI;
+ int16_t x, y, w, h;
+
+ if (clip) {
+ // Clipping reduces the number of pixels that are
+ // filled, allowing more complex shapes to be drawn
+ // in the allotted time.
+ bounds(r, x, y, w, h);
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(SCISSOR_XY(x, y));
+ cmd.cmd(SCISSOR_SIZE(w, h));
+ }
+
+ Polygon p(cmd);
+ p.begin_fill();
+ p.begin_loop();
+ for (r.start();r.has_more();r.next()) {
+ p(r.x * 16, r.y * 16);
+ if (r.end_of_loop()) {
+ p.end_loop();
+ p.begin_loop();
+ }
+ }
+ p.end_loop();
+ p.end_fill();
+ if (clip)
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+
+ void shadow(poly_reader_t r, uint8_t offset) {
+ #if FTDI_API_LEVEL >= 810
+ using namespace FTDI;
+ cmd.cmd(VERTEX_TRANSLATE_X(offset * 16));
+ cmd.cmd(VERTEX_TRANSLATE_Y(offset * 16));
+ fill(r, false);
+ cmd.cmd(VERTEX_TRANSLATE_X(0));
+ cmd.cmd(VERTEX_TRANSLATE_Y(0));
+ #endif
+ }
+
+ // Strokes a polygon with the current COLOR_RGB
+ void stroke(poly_reader_t r) {
+ using namespace FTDI;
+ Polygon p(cmd);
+ p.begin_stroke();
+ p.begin_loop();
+ for (r.start();r.has_more(); r.next()) {
+ p(r.x * 16, r.y * 16);
+ if (r.end_of_loop()) {
+ p.end_loop();
+ p.begin_loop();
+ }
+ }
+ p.end_loop();
+ p.end_stroke();
+ }
+
+ // Compute the bounds of a polygon
+ void bounds(poly_reader_t r, int16_t &x, int16_t &y, int16_t &w, int16_t &h) {
+ int16_t x_min = INT16_MAX;
+ int16_t y_min = INT16_MAX;
+ int16_t x_max = INT16_MIN;
+ int16_t y_max = INT16_MIN;
+ for (r.start(); r.has_more(); r.next()) {
+ x_min = min(x_min, int16_t(r.x));
+ x_max = max(x_max, int16_t(r.x));
+ y_min = min(y_min, int16_t(r.y));
+ y_max = max(y_max, int16_t(r.y));
+ }
+ x = x_min;
+ y = y_min;
+ w = x_max - x_min;
+ h = y_max - y_min;
+ }
+
+ /**
+ * Draw shaped buttons. Buttons are drawn out of a polygon which is
+ * filled and stroked on top of a drop shadow. The button will
+ * become "pushed" when touched.
+ */
+
+ void button_fill(const uint32_t color) {
+ btn_fill_color = color;
+ }
+
+ void button_stroke(const uint32_t color, const uint8_t width) {
+ btn_stroke_color = color;
+ btn_stroke_width = width;
+ }
+
+ void button_shadow(const uint32_t color, const uint8_t depth) {
+ btn_shadow_color = color;
+ btn_shadow_depth = depth;
+ }
+
+ void button(const uint8_t tag, poly_reader_t r, uint8_t style = REGULAR) {
+ using namespace FTDI;
+ // Draw the shadow
+ #if FTDI_API_LEVEL >= 810
+ if (mode & BACKGROUND && style & SHADOW) {
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(TAG(tag));
+ cmd.cmd(VERTEX_TRANSLATE_X(btn_shadow_depth * 16));
+ cmd.cmd(VERTEX_TRANSLATE_Y(btn_shadow_depth * 16));
+ cmd.cmd(COLOR_RGB(btn_shadow_color));
+ fill(r, false);
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+ #endif
+
+ if (mode & FOREGROUND) {
+ cmd.cmd(SAVE_CONTEXT());
+ #if FTDI_API_LEVEL >= 810
+ if (EventLoop::get_pressed_tag() == tag) {
+ // "Push" the button
+ cmd.cmd(VERTEX_TRANSLATE_X(btn_shadow_depth * 16));
+ cmd.cmd(VERTEX_TRANSLATE_Y(btn_shadow_depth * 16));
+ }
+ #endif
+ // Draw the fill and stroke
+ cmd.cmd(TAG(tag));
+ if (style & FILL) {
+ cmd.cmd(COLOR_RGB(btn_fill_color));
+ fill(r, false);
+ }
+ if (style & STROKE) {
+ cmd.cmd(COLOR_RGB(btn_stroke_color));
+ cmd.cmd(LINE_WIDTH(btn_stroke_width));
+ stroke(r);
+ }
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+ }
+
+ void color(const uint32_t color) {
+ cmd.cmd(FTDI::COLOR_RGB(color));
+ }
+};
+
+typedef GenericPolyUI<> PolyUI;
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/polygon.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/polygon.h
new file mode 100644
index 0000000..3dc80bb
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/polygon.h
@@ -0,0 +1,96 @@
+/*************
+ * polygon.h *
+ *************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * The Polygon class helps drawing filled or stroked polygons on the FTDI EVE:
+ *
+ * CommandProcessor cmd;
+ * cmd.cmd(COLOR_RGB(0x00FF00));
+ *
+ * Polygon p(cmd);
+ * p.begin_fill();
+ * p.begin_loop();
+ * p(10,10);
+ * p(20,10);
+ * p(20,20);
+ * p(10,20);
+ * p.end_loop();
+ * p.begin_loop();
+ * ... // Additional closed paths
+ * p.end_loop();
+ * ...
+ * p.end_fill();
+ *
+ * Based on the example from "Application Note AN_334, FT801 Polygon Application":
+ *
+ * https://brtchip.com/wp-content/uploads/Support/Documentation/Application_Notes/ICs/EVE/AN_334-FT801_Polygon_Application.pdf
+ */
+
+namespace FTDI {
+ class Polygon {
+ private:
+ FTDI::begin_t path_initiator = FTDI::LINE_STRIP;
+
+ public:
+ CommandProcessor &cmd;
+
+ Polygon(CommandProcessor &c) : cmd(c) {}
+
+ void begin_fill() {
+ using namespace FTDI;
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(TAG_MASK(0));
+ cmd.cmd(CLEAR(0,1,0));
+ cmd.cmd(COLOR_MASK(0,0,0,0));
+ cmd.cmd(STENCIL_OP(STENCIL_OP_KEEP, STENCIL_OP_INVERT));
+ cmd.cmd(STENCIL_FUNC(STENCIL_FUNC_ALWAYS, 255, 255));
+ // Drawing the edge strip along scan lines
+ // seems to yield the best performance
+ #if ENABLED(TOUCH_UI_PORTRAIT)
+ path_initiator = EDGE_STRIP_B;
+ #else
+ path_initiator = EDGE_STRIP_R;
+ #endif
+ }
+
+ // Specify a clipping rectangle to paint fewer pixels and reduce rendering time, otherwise all pixels will be painted.
+ void end_fill(const int16_t x1 = 0, const int16_t y1 = 0, const int16_t x2 = display_width * 16, const int16_t y2 = display_height * 16) {
+ using namespace FTDI;
+ cmd.cmd(RESTORE_CONTEXT());
+
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(STENCIL_FUNC(STENCIL_FUNC_NOTEQUAL, 0, 255));
+ cmd.cmd(BEGIN(RECTS));
+ cmd.cmd(VERTEX2F(x1, y1));
+ cmd.cmd(VERTEX2F(x2, y2));
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+
+ void begin_stroke() {path_initiator = FTDI::LINE_STRIP;}
+ void begin_loop() {cmd.cmd(FTDI::BEGIN(path_initiator));}
+ void end_stroke() {}
+ void end_loop() {}
+
+ void operator()(const uint16_t x, const uint16_t y) {cmd.cmd(FTDI::VERTEX2F(x, y));}
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/rgb_t.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/rgb_t.h
new file mode 100644
index 0000000..62762ee
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/rgb_t.h
@@ -0,0 +1,84 @@
+/***********
+ * rgb_t.h *
+ ***********/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * Implementation of hsl_to_rgb as constexpr functions based on:
+ *
+ * https://www.rapidtables.com/convert/color/hsl-to-rgb.html
+ */
+
+constexpr float _hsl_fmod(float x, float y) {
+ return x - int(x/y)*y;
+}
+
+constexpr float _hsl_c(float, float S, float L) {
+ return (1.0f - fabs(2*L-1.0f)) * S;
+}
+
+constexpr float _hsl_x(float H, float S, float L) {
+ return _hsl_c(H,S,L) * (1.0f - fabs(_hsl_fmod(H/60, 2) - 1));
+}
+
+constexpr float _hsl_m(float H, float S, float L) {
+ return L - _hsl_c(H,S,L)/2;
+}
+
+constexpr float _hsl_rgb(float H, float S, float L, float r, float g, float b) {
+ return ((uint32_t((r + _hsl_m(H,S,L))*255+0.5) << 16) |
+ (uint32_t((g + _hsl_m(H,S,L))*255+0.5) << 8) |
+ (uint32_t((b + _hsl_m(H,S,L))*255+0.5) << 0));
+}
+
+constexpr uint32_t hsl_to_rgb(float H, float S, float L) {
+ return (H < 60) ? _hsl_rgb(H,S,L,_hsl_c(H,S,L), _hsl_x(H,S,L), 0) :
+ (H < 120) ? _hsl_rgb(H,S,L,_hsl_x(H,S,L), _hsl_c(H,S,L), 0) :
+ (H < 180) ? _hsl_rgb(H,S,L, 0, _hsl_c(H,S,L), _hsl_x(H,S,L)) :
+ (H < 240) ? _hsl_rgb(H,S,L, 0, _hsl_x(H,S,L), _hsl_c(H,S,L)) :
+ (H < 300) ? _hsl_rgb(H,S,L,_hsl_x(H,S,L), 0, _hsl_c(H,S,L)) :
+ _hsl_rgb(H,S,L,_hsl_c(H,S,L), 0, _hsl_x(H,S,L));
+}
+
+/**
+ * Structure for RGB colors
+ */
+struct rgb_t {
+ union {
+ struct {
+ uint8_t b,g,r,a;
+ };
+ uint32_t packed;
+ };
+
+ rgb_t() : packed(0) {}
+ rgb_t(uint32_t rgb) : packed(rgb) {}
+ rgb_t(uint8_t r, uint8_t g, uint8_t b) : b(b), g(g), r(r), a(0) {}
+ operator uint32_t() const {return packed;};
+
+ static void lerp(float t, const rgb_t a, const rgb_t b, rgb_t &c) {
+ c.r = a.r + t * (b.r - a.r);
+ c.g = a.g + t * (b.g - a.g);
+ c.b = a.b + t * (b.b - a.b);
+ }
+
+ uint8_t luminance() const {return 0.299*r + 0.587*g + 0.114*b;}
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp
new file mode 100644
index 0000000..44836ce
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp
@@ -0,0 +1,104 @@
+/******************
+ * screen_types.h *
+ ******************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+/********************** VIRTUAL DISPATCH DATA TYPE ******************************/
+
+uint8_t ScreenRef::lookupScreen(onRedraw_func_t onRedraw_ptr) {
+ for (uint8_t type = 0; type < tableSize(); type++) {
+ if (GET_METHOD(type, onRedraw) == onRedraw_ptr) {
+ return type;
+ }
+ }
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_START();
+ SERIAL_ECHOPGM("Screen not found: ", (uintptr_t) onRedraw_ptr);
+ #endif
+ return 0xFF;
+}
+
+void ScreenRef::setScreen(onRedraw_func_t onRedraw_ptr) {
+ uint8_t type = lookupScreen(onRedraw_ptr);
+ if (type != 0xFF) {
+ setType(type);
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("New screen: ", type);
+ #endif
+ }
+}
+
+void ScreenRef::initializeAll() {
+ for (uint8_t type = 0; type < tableSize(); type++)
+ GET_METHOD(type, onStartup)();
+}
+
+/********************** SCREEN STACK ******************************/
+
+void ScreenStack::start() {
+ initializeAll();
+ onEntry();
+}
+
+void ScreenStack::push(onRedraw_func_t onRedraw_ptr) {
+ stack[3] = stack[2];
+ stack[2] = stack[1];
+ stack[1] = stack[0];
+ stack[0] = lookupScreen(onRedraw_ptr);
+}
+
+void ScreenStack::push() {
+ stack[3] = stack[2];
+ stack[2] = stack[1];
+ stack[1] = stack[0];
+ stack[0] = getType();
+}
+
+void ScreenStack::pop() {
+ setType(stack[0]);
+ forget();
+}
+
+void ScreenStack::forget() {
+ stack[0] = stack[1];
+ stack[1] = stack[2];
+ stack[2] = stack[3];
+ stack[3] = 0;
+}
+
+void ScreenStack::goTo(onRedraw_func_t s) {
+ push();
+ onExit();
+ setScreen(s);
+ onEntry();
+}
+
+void ScreenStack::goBack() {
+ onExit();
+ pop();
+ onEntry();
+}
+
+ScreenStack current_screen;
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h
new file mode 100644
index 0000000..a13ab8e
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h
@@ -0,0 +1,243 @@
+/********************
+ * screen_types.cpp *
+ ********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+typedef enum {
+ BACKGROUND = 1,
+ FOREGROUND = 2,
+ BOTH = 3
+} draw_mode_t;
+
+ /********************** VIRTUAL DISPATCH DATA TYPE ******************************/
+
+// True virtual classes are extremely expensive on the Arduino
+// as the compiler stores the virtual function tables in RAM.
+// We invent a data type called ScreenRef that gives us
+// polymorphism by mapping an ID to virtual methods on various
+// classes. This works by keeping a table in PROGMEM of pointers
+// to static methods.
+
+#define DECL_SCREEN(className) { \
+ className::onStartup, \
+ className::onEntry, \
+ className::onExit, \
+ className::onIdle, \
+ className::onRefresh, \
+ className::onRedraw, \
+ className::onTouchStart, \
+ className::onTouchHeld, \
+ className::onTouchEnd \
+}
+
+#define GET_METHOD(type, method) reinterpret_cast(pgm_read_ptr_far(&functionTable[type].method##_ptr))
+#define SCREEN_TABLE PROGMEM const ScreenRef::table_t ScreenRef::functionTable[] =
+#define SCREEN_TABLE_POST size_t ScreenRef::tableSize() { \
+ constexpr size_t siz = sizeof(functionTable)/sizeof(functionTable[0]); \
+ static_assert(siz > 0, "The screen table is empty!"); \
+ return siz; \
+ }
+
+class ScreenRef {
+ protected:
+ typedef void onStartup_func_t();
+ typedef void onEntry_func_t();
+ typedef void onExit_func_t();
+ typedef void onIdle_func_t();
+ typedef void onRefresh_func_t();
+ typedef void onRedraw_func_t(draw_mode_t);
+ typedef bool onTouchStart_func_t(uint8_t);
+ typedef bool onTouchHeld_func_t(uint8_t);
+ typedef bool onTouchEnd_func_t(uint8_t);
+
+ private:
+ typedef struct {
+ onStartup_func_t *onStartup_ptr;
+ onEntry_func_t *onEntry_ptr;
+ onExit_func_t *onExit_ptr;
+ onIdle_func_t *onIdle_ptr;
+ onRefresh_func_t *onRefresh_ptr;
+ onRedraw_func_t *onRedraw_ptr;
+ onTouchStart_func_t *onTouchStart_ptr;
+ onTouchHeld_func_t *onTouchHeld_ptr;
+ onTouchEnd_func_t *onTouchEnd_ptr;
+ } table_t;
+
+ uint8_t type = 0;
+ static PROGMEM const table_t functionTable[];
+
+ public:
+ static size_t tableSize();
+
+ uint8_t getType() {return type;}
+ void setType(uint8_t t) {type = t;}
+
+ uint8_t lookupScreen(onRedraw_func_t onRedraw_ptr);
+
+ void setScreen(onRedraw_func_t onRedraw_ptr);
+
+ void onStartup() {GET_METHOD(type, onStartup)();}
+ void onEntry() {GET_METHOD(type, onEntry)();}
+ void onExit() {GET_METHOD(type, onExit)();}
+ void onIdle() {GET_METHOD(type, onIdle)();}
+ void onRefresh() {GET_METHOD(type, onRefresh)();}
+ void onRedraw(draw_mode_t dm) {GET_METHOD(type, onRedraw)(dm);}
+ bool onTouchStart(uint8_t tag) {return GET_METHOD(type, onTouchStart)(tag);}
+ bool onTouchHeld(uint8_t tag) {return GET_METHOD(type, onTouchHeld)(tag);}
+ bool onTouchEnd(uint8_t tag) {return GET_METHOD(type, onTouchEnd)(tag);}
+
+ void initializeAll();
+};
+
+/********************** SCREEN STACK ******************************/
+
+// To conserve dynamic memory, the screen stack is hard-coded to
+// have four values, allowing a menu of up to four levels.
+
+class ScreenStack : public ScreenRef {
+ private:
+ uint8_t stack[4];
+
+ public:
+ void start();
+ void push(onRedraw_func_t);
+ void push();
+ void pop();
+ void forget();
+ void goTo(onRedraw_func_t);
+ void goBack();
+
+ uint8_t peek() {return stack[0];}
+ uint8_t getScreen() {return getType();}
+};
+
+extern ScreenStack current_screen;
+
+/********************** BASE SCREEN CLASS ******************************/
+
+/* UIScreen is the base class for all user interface screens.
+ */
+class UIScreen {
+ public:
+ static void onStartup() {}
+ static void onEntry() {current_screen.onRefresh();}
+ static void onExit() {}
+ static void onIdle() {}
+ static bool onTouchStart(uint8_t) {return true;}
+ static bool onTouchHeld(uint8_t) {return false;}
+ static bool onTouchEnd(uint8_t) {return true;}
+};
+
+#define PUSH_SCREEN(screen) current_screen.push(screen::onRedraw)
+#define GOTO_SCREEN(screen) current_screen.goTo(screen::onRedraw)
+#define GOTO_PREVIOUS() current_screen.goBack();
+#define AT_SCREEN(screen) (current_screen.getType() == current_screen.lookupScreen(screen::onRedraw))
+#define IS_PARENT_SCREEN(screen) (current_screen.peek() == current_screen.lookupScreen(screen::onRedraw))
+
+/************************** CACHED VS UNCACHED SCREENS ***************************/
+
+class UncachedScreen {
+ public:
+ static void onRefresh() {
+ using namespace FTDI;
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART);
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd);
+ #endif
+
+ current_screen.onRedraw(BOTH);
+
+ cmd.cmd(DL::DL_DISPLAY);
+ cmd.cmd(CMD_SWAP);
+ cmd.execute();
+ }
+};
+
+template
+class CachedScreen {
+ protected:
+ static void gfxError() {
+ using namespace FTDI;
+ CommandProcessor cmd;
+ cmd.cmd(CMD_DLSTART)
+ .cmd(CLEAR(true,true,true))
+ .font(30)
+ .text(0, 0, display_width, display_height, F("GFX MEM FULL"));
+ }
+
+ static bool storeBackground() {
+ DLCache dlcache(DL_SLOT);
+ if (!dlcache.store(DL_SIZE)) {
+ SERIAL_ECHO_MSG("CachedScreen::storeBackground() failed: not enough DL cache space");
+ gfxError(); // Try to cache a shorter error message instead.
+ dlcache.store(DL_SIZE);
+ return false;
+ }
+ return true;
+ }
+
+ static void repaintBackground() {
+ using namespace FTDI;
+ DLCache dlcache(DL_SLOT);
+ CommandProcessor cmd;
+
+ cmd.cmd(CMD_DLSTART);
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd);
+ #endif
+ current_screen.onRedraw(BACKGROUND);
+
+ dlcache.store(DL_SIZE);
+ }
+
+ public:
+ static void onRefresh() {
+ #if ENABLED(TOUCH_UI_DEBUG)
+ const uint32_t start_time = millis();
+ #endif
+ using namespace FTDI;
+ DLCache dlcache(DL_SLOT);
+ CommandProcessor cmd;
+
+ cmd.cmd(CMD_DLSTART);
+
+ if (dlcache.has_data()) {
+ dlcache.append();
+ }
+ else {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ load_utf8_bitmaps(cmd);
+ #endif
+ current_screen.onRedraw(BACKGROUND);
+ dlcache.store(DL_SIZE);
+ }
+
+ current_screen.onRedraw(FOREGROUND);
+
+ cmd.cmd(DL::DL_DISPLAY);
+ cmd.cmd(CMD_SWAP);
+ cmd.execute();
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHOLNPGM("Time to draw screen (ms): ", millis() - start_time);
+ #endif
+ }
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_list.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_list.h
new file mode 100644
index 0000000..b204f04
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_list.h
@@ -0,0 +1,38 @@
+/****************
+ * sound_list.h *
+ ****************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+class SoundList {
+ private:
+ static PROGMEM const struct list_t {
+ const char * const PROGMEM name;
+ const FTDI::SoundPlayer::sound_t* data;
+ } list[];
+ public:
+ static const uint8_t n;
+ static const char* name(uint8_t val) {
+ return (const char* ) pgm_read_ptr_far(&list[val].name);
+ }
+ static FTDI::SoundPlayer::sound_t* data(uint8_t val) {
+ return (FTDI::SoundPlayer::sound_t*) pgm_read_ptr_far(&list[val].data);
+ }
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp
new file mode 100644
index 0000000..47bf79e
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp
@@ -0,0 +1,108 @@
+/********************
+ * sound_player.cpp *
+ ********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+namespace FTDI {
+ SoundPlayer sound; // Global sound player object
+
+ void SoundPlayer::set_volume(uint8_t vol) {
+ CLCD::mem_write_8(REG::VOL_SOUND, vol);
+ }
+
+ uint8_t SoundPlayer::get_volume() {
+ return CLCD::mem_read_8(REG::VOL_SOUND);
+ }
+
+ void SoundPlayer::play(effect_t effect, note_t note) {
+
+ #if ENABLED(TOUCH_UI_DEBUG)
+ SERIAL_ECHO_MSG("Playing note ", note, ", instrument ", effect);
+ #endif
+
+ // Play the note
+ CLCD::mem_write_16(REG::SOUND, (note == REST) ? 0 : (((note ? note : NOTE_C4) << 8) | effect));
+ CLCD::mem_write_8(REG::PLAY, 1);
+ }
+
+ note_t SoundPlayer::frequency_to_midi_note(const uint16_t frequency_hz) {
+ const float f0 = 440;
+ return note_t(NOTE_A4 + (log(frequency_hz)-log(f0))*12/log(2) + 0.5);
+ }
+
+ // Plays a tone of a given frequency and duration. Since the FTDI FT810 only
+ // supports MIDI notes, we round down to the nearest note.
+
+ void SoundPlayer::play_tone(const uint16_t frequency_hz, const uint16_t duration_ms) {
+ play(ORGAN, frequency_to_midi_note(frequency_hz));
+
+ // Schedule silence to squelch the note after the duration expires.
+ sequence = silence;
+ wait = duration_ms;
+ timer.start();
+ }
+
+ void SoundPlayer::play(const sound_t *seq, play_mode_t mode) {
+ sequence = seq;
+ wait = 250; // Adding this delay causes the note to not be clipped, not sure why.
+ timer.start();
+
+ if (mode == PLAY_ASYNCHRONOUS) return;
+
+ // If playing synchronously, then play all the notes here
+
+ while (has_more_notes()) {
+ onIdle();
+ TERN_(TOUCH_UI_FTDI_EVE, ExtUI::yield());
+ }
+ }
+
+ bool SoundPlayer::is_sound_playing() {
+ return CLCD::mem_read_8( REG::PLAY ) & 0x1;
+ }
+
+ void SoundPlayer::onIdle() {
+ if (!sequence) return;
+
+ const bool ready_for_next_note = (wait == 0) ? !is_sound_playing() : timer.elapsed(wait);
+
+ if (ready_for_next_note) {
+ const effect_t fx = effect_t(pgm_read_byte(&sequence->effect));
+ const note_t nt = note_t(pgm_read_byte(&sequence->note));
+ const uint32_t ms = uint32_t(pgm_read_byte(&sequence->sixteenths)) * 1000 / 16;
+
+ if (ms == 0 && fx == SILENCE && nt == END_SONG) {
+ sequence = 0;
+ play(SILENCE, REST);
+ }
+ else {
+ wait = ms;
+ timer.start();
+ play(fx, nt);
+ sequence++;
+ }
+ }
+ }
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.h
new file mode 100644
index 0000000..3ba39b8
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.h
@@ -0,0 +1,70 @@
+/******************
+ * sound_player.h *
+ ******************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+namespace FTDI {
+ typedef enum {
+ PLAY_ASYNCHRONOUS,
+ PLAY_SYNCHRONOUS
+ } play_mode_t;
+
+ class SoundPlayer {
+ typedef FTDI::ftdi_registers REG;
+ typedef FTDI::ftdi_memory_map MAP;
+
+ public:
+ struct sound_t {
+ effect_t effect; // The sound effect number
+ note_t note; // The MIDI note value
+ uint16_t sixteenths; // Duration of note, in sixteeths of a second, or zero to play to completion
+ };
+
+ const uint8_t WAIT = 0;
+
+ private:
+ const sound_t *sequence;
+ tiny_timer_t timer;
+ tiny_time_t wait;
+
+ note_t frequency_to_midi_note(const uint16_t frequency);
+
+ public:
+ static void set_volume(uint8_t volume);
+ static uint8_t get_volume();
+
+ static void play(effect_t effect, note_t note = NOTE_C4);
+ static bool is_sound_playing();
+
+ void play(const sound_t *seq, play_mode_t mode = PLAY_SYNCHRONOUS);
+ void play_tone(const uint16_t frequency_hz, const uint16_t duration_ms);
+ bool has_more_notes() {return sequence != 0;};
+
+ void onIdle();
+ };
+
+ extern SoundPlayer sound;
+
+ const PROGMEM SoundPlayer::sound_t silence[] = {
+ {SILENCE, END_SONG, 0}
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp
new file mode 100644
index 0000000..d2f95d1
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp
@@ -0,0 +1,149 @@
+/****************
+ * text_box.cpp *
+ ****************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+#define IS_LINE_SEPARATOR(c) c == '\n' || c == '\t'
+#define IS_WORD_SEPARATOR(c) c == ' '
+#define IS_SEPARATOR(c) IS_LINE_SEPARATOR(c) || IS_WORD_SEPARATOR(c)
+
+namespace FTDI {
+ /**
+ * Given a str, end will be set to the position at which a line needs to
+ * be broken so that the display width is less than w. The line will also
+ * be broken after a '\n'. Returns the display width of the line.
+ */
+ static uint16_t find_line_break(const FontMetrics &utf8_fm, const CLCD::FontMetrics &clcd_fm, const uint16_t w, const char *start, const char *&end, bool use_utf8) {
+ const char *p = start;
+ end = start;
+ uint16_t lw = 0, result = 0;
+ for (;;) {
+ const char *next = p;
+ const utf8_char_t c = get_utf8_char_and_inc(next);
+ // Decide whether to break the string at this location
+ if (IS_SEPARATOR(c) || c == '\0' ) {
+ end = p;
+ result = lw;
+ }
+ if (IS_LINE_SEPARATOR(c) || c == '\0') break;
+ // Measure the next character
+ const uint16_t cw = use_utf8 ? utf8_fm.get_char_width(c) : clcd_fm.char_widths[(uint8_t)c];
+ // Stop processing once string exceeds the display width
+ if (lw + cw > w) break;
+ // Now add the length of the current character to the tally.
+ lw += cw;
+ p = next;
+ }
+ if (end == start) {
+ end = p;
+ result = lw;
+ }
+ return result;
+ }
+
+ /**
+ * This function returns a measurements of the word-wrapped text box.
+ */
+ static void measure_text_box(const FontMetrics &utf8_fm, const CLCD::FontMetrics &clcd_fm, const char *str, uint16_t &width, uint16_t &height, bool use_utf8) {
+ const char *line_start = (const char*)str;
+ const char *line_end;
+ const uint16_t wrap_width = width;
+ width = height = 0;
+ for (;;) {
+ const uint16_t line_width = find_line_break(utf8_fm, clcd_fm, wrap_width, line_start, line_end, use_utf8);
+ width = max(width, line_width);
+ height += utf8_fm.get_height();
+ if (IS_SEPARATOR(*line_end)) line_end++;
+ if (*line_end == '\0') break;
+ if (line_end == line_start) break;
+ line_start = line_end;
+ }
+ }
+
+ /**
+ * This function draws text inside a bounding box, doing word wrapping and using the largest font that will fit.
+ */
+ void draw_text_box(CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options, uint8_t font) {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ const bool use_utf8 = has_utf8_chars(str);
+ #else
+ constexpr bool use_utf8 = false;
+ #endif
+ uint16_t box_width, box_height;
+
+ FontMetrics utf8_fm(font);
+ CLCD::FontMetrics clcd_fm;
+ clcd_fm.load(font);
+
+ // Shrink the font until we find a font that fits
+ for (;;) {
+ box_width = w;
+ measure_text_box(utf8_fm, clcd_fm, str, box_width, box_height, use_utf8);
+ if (box_width <= (uint16_t)w && box_height <= (uint16_t)h) break;
+ if (font == 26) break;
+ utf8_fm.load(--font);
+ clcd_fm.load(font);
+ }
+
+ const uint16_t dx = (options & OPT_RIGHTX) ? w :
+ (options & OPT_CENTERX) ? w / 2 : 0,
+ dy = (options & OPT_BOTTOMY) ? (h - box_height) :
+ (options & OPT_CENTERY) ? (h - box_height) / 2 : 0;
+
+ const char *line_start = str, *line_end;
+ for (;;) {
+ find_line_break(utf8_fm, clcd_fm, w, line_start, line_end, use_utf8);
+
+ const size_t line_len = line_end - line_start;
+ if (line_len) {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ if (use_utf8)
+ draw_utf8_text(cmd, x + dx, y + dy, line_start, utf8_fm.fs, options & ~(OPT_CENTERY | OPT_BOTTOMY), line_len);
+ else
+ #endif
+ {
+ cmd.CLCD::CommandFifo::text(x + dx, y + dy, font, options & ~(OPT_CENTERY | OPT_BOTTOMY));
+ cmd.CLCD::CommandFifo::str(line_start, line_len);
+ }
+ }
+ y += utf8_fm.get_height();
+
+ if (IS_SEPARATOR(*line_end)) line_end++;
+ if (*line_end == '\0') break;
+ if (line_end == line_start) break;
+ line_start = line_end;
+ }
+ }
+
+ void draw_text_box(CommandProcessor& cmd, int x, int y, int w, int h, FSTR_P fstr, uint16_t options, uint8_t font) {
+ #ifdef __AVR__
+ char str[strlen_P(FTOP(fstr)) + 1];
+ strcpy_P(str, FTOP(fstr));
+ draw_text_box(cmd, x, y, w, h, (const char*) str, options, font);
+ #else
+ draw_text_box(cmd, x, y, w, h, FTOP(fstr), options, font);
+ #endif
+ }
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h
new file mode 100644
index 0000000..cc70234
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h
@@ -0,0 +1,32 @@
+/**************
+ * text_box.h *
+ **************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * This function draws text inside a bounding box, doing word wrapping and using the largest font that will fit.
+ */
+namespace FTDI {
+ constexpr uint16_t OPT_BOTTOMY = 0x1000; // Non-standard
+
+ void draw_text_box(class CommandProcessor& cmd, int x, int y, int w, int h, FSTR_P str, uint16_t options = 0, uint8_t font = 31);
+ void draw_text_box(class CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options = 0, uint8_t font = 31);
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp
new file mode 100644
index 0000000..a6d014b
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp
@@ -0,0 +1,87 @@
+/*********************
+ * text_ellipsis.cpp *
+ *********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+namespace FTDI {
+
+ /**
+ * Helper function for drawing text with ellipses. The str buffer may be modified and should have space for up to two extra characters.
+ */
+ static void _draw_text_with_ellipsis(CommandProcessor& cmd, int16_t x, int16_t y, int16_t w, int16_t h, char *str, uint16_t options, uint8_t font) {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ const bool use_utf8 = has_utf8_chars(str);
+ #define CHAR_WIDTH(c) use_utf8 ? utf8_fm.get_char_width(c) : clcd_fm.char_widths[(uint8_t)c]
+ #else
+ constexpr bool use_utf8 = false;
+ #define CHAR_WIDTH(c) utf8_fm.get_char_width(c)
+ #endif
+ FontMetrics utf8_fm(font);
+ CLCD::FontMetrics clcd_fm;
+ clcd_fm.load(font);
+ const int16_t ellipsisWidth = utf8_fm.get_char_width('.') * 3;
+
+ // Compute the total line length, as well as
+ // the location in the string where it can
+ // split and still allow the ellipsis to fit.
+ int16_t lineWidth = 0;
+ char *breakPoint = str;
+ const char *next = str;
+ while (*next) {
+ const utf8_char_t c = get_utf8_char_and_inc(next);
+ lineWidth += CHAR_WIDTH(c);
+ if (lineWidth + ellipsisWidth < w)
+ breakPoint = (char*)next;
+ }
+
+ if (lineWidth > w)
+ strcpy_P(breakPoint, PSTR("..."));
+
+ cmd.apply_text_alignment(x, y, w, h, options);
+ if (use_utf8) {
+ TERN_(TOUCH_UI_USE_UTF8, draw_utf8_text(cmd, x, y, str, font_size_t::from_romfont(font), options));
+ }
+ else {
+ cmd.CLCD::CommandFifo::text(x, y, font, options);
+ cmd.CLCD::CommandFifo::str(str);
+ }
+ }
+
+ /**
+ * These functions draws text inside a bounding box, truncating the text and
+ * adding ellipsis if the text does not fit.
+ */
+ void draw_text_with_ellipsis(CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options, uint8_t font) {
+ char tmp[strlen(str) + 3];
+ strcpy(tmp, str);
+ _draw_text_with_ellipsis(cmd, x, y, w, h, tmp, options, font);
+ }
+
+ void draw_text_with_ellipsis(CommandProcessor& cmd, int x, int y, int w, int h, FSTR_P fstr, uint16_t options, uint8_t font) {
+ char tmp[strlen_P(FTOP(fstr)) + 3];
+ strcpy_P(tmp, FTOP(fstr));
+ _draw_text_with_ellipsis(cmd, x, y, w, h, tmp, options, font);
+ }
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h
new file mode 100644
index 0000000..0c6b202
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h
@@ -0,0 +1,31 @@
+/*******************
+ * text_ellipsis.h *
+ *******************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2020 - SynDaver Labs, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/**
+ * This function draws text inside a bounding box, truncating the text and
+ * showing ellipsis if it does not fit.
+ */
+namespace FTDI {
+ void draw_text_with_ellipsis(class CommandProcessor& cmd, int x, int y, int w, int h, FSTR_P str, uint16_t options = 0, uint8_t font = 31);
+ void draw_text_with_ellipsis(class CommandProcessor& cmd, int x, int y, int w, int h, const char *str, uint16_t options = 0, uint8_t font = 31);
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.cpp
new file mode 100644
index 0000000..5219c0d
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.cpp
@@ -0,0 +1,39 @@
+/******************
+ * tiny_timer.cpp *
+ ******************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+bool tiny_timer_t::elapsed(tiny_time_t duration) {
+ uint8_t now = tiny_time_t::tiny_time(
+ TERN(__MARLIN_FIRMWARE__, ExtUI::safe_millis(), millis())
+ );
+ uint8_t elapsed = now - _start;
+ return elapsed >= duration._duration;
+}
+
+void tiny_timer_t::start() {
+ _start = tiny_time_t::tiny_time(
+ TERN(__MARLIN_FIRMWARE__, ExtUI::safe_millis(), millis())
+ );
+}
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.h
new file mode 100644
index 0000000..576567c
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.h
@@ -0,0 +1,56 @@
+/****************
+ * tiny_timer.h *
+ ****************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/* Helpful Reference:
+ *
+ * https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover
+ */
+
+/* tiny_interval_t downsamples a 32-bit millis() value
+ into a 8-bit value which can record periods of
+ a few seconds with a roughly 1/16th of second
+ resolution. This allows us to measure small
+ intervals without needing to use four-byte counters.
+ */
+class tiny_time_t {
+ private:
+ friend class tiny_timer_t;
+ uint8_t _duration;
+
+ static uint8_t tiny_time(uint32_t ms) {return ceil(float(ms) / 64);};
+
+ public:
+ tiny_time_t() : _duration(0) {}
+ tiny_time_t(uint32_t ms) : _duration(tiny_time(ms)) {}
+ tiny_time_t & operator= (uint32_t ms) {_duration = tiny_time(ms); return *this;}
+ bool operator == (uint32_t ms) {return _duration == tiny_time(ms);}
+};
+
+class tiny_timer_t {
+ private:
+ uint8_t _start;
+
+ public:
+ void start();
+ bool elapsed(tiny_time_t interval);
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/README.txt b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/README.txt
new file mode 100644
index 0000000..36808d2
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/README.txt
@@ -0,0 +1,40 @@
+
+FTDI EVE Unicode Rendering
+--------------------------
+
+The FTDI EVE chips have several fonts in ROM, but these fonts only contain a
+subset of ASCII characters. Notably, this excludes diacritics and accents
+used in most Western languages.
+
+While the FTDI EVE has the capability for user-defined fonts, such fonts only
+support 127 character positions, making them as limiting as the built-in fonts.
+
+As a further complication, high resolution TFT displays require high resolution
+fonts. It is not feasible to put a complete international font into the limited
+flash memory of most microprocessors.
+
+To work around these limitations, this library uses a custom font renderer with
+the following characteristics:
+
+ 1) Rather than providing bitmaps for different font sizes, it uses a single
+ bitmap for the largest font size (romfont 31) and emulates other sizes by
+ scaling the bitmaps using BITMAP_TRANSFORM.
+
+ 2) Rather than loading an entire font, it combines symbols from romfont 31
+ with a limited number of symbols from a custom font. For accented letters,
+ the rendering code combine basic letter shapes from romfont 31 with
+ bitmaps containing only the accent themselves.
+
+ 3) The custom bitmap is RLE compressed into PROGMEM. For accents, which have
+ a fairly small number of non-white pixels, the savings are significant.
+
+These characteristics enable an alphabet for Western languages to be
+synthesized from only a few dozen custom symbols and modest PROGMEM use (~10k)
+
+The text layout is done by the code in "unicode.cpp" with the help of one of
+more character renderers (e.g. "western_char_set.cpp"). Each character render
+is responsible for loading the necessary bitmap data into RAMG and drawing
+characters as requested.
+
+To add symbols for other languages, it will only be necessary to make a bitmap
+and implement a corresponding character renderer.
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.cpp
new file mode 100644
index 0000000..1c193ad
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.cpp
@@ -0,0 +1,139 @@
+/************************
+ * cyrillic_char_set.cpp *
+ ************************/
+
+/****************************************************************************
+ * Written By Kirill Shashlov 2020 *
+ * Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if ALL(FTDI_EXTENDED, TOUCH_UI_USE_UTF8, TOUCH_UI_UTF8_CYRILLIC_CHARSET)
+
+ #include "cyrillic_char_set_bitmap_31.h"
+
+ #define NUM_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
+
+ #define UTF8(A) uint16_t(utf8(U##A))
+
+ using namespace FTDI;
+
+ constexpr static uint8_t cyrillic_font_handle = 6;
+
+ uint32_t FTDI::CyrillicCharSet::bitmap_addr;
+
+ /**
+ * Load bitmap data into RAMG. This function is called once at the start
+ * of the program.
+ *
+ * Parameters:
+ *
+ * addr - Address in RAMG where the font data is written
+ *
+ * Returns: Last wrote address
+ */
+
+ uint32_t FTDI::CyrillicCharSet::load_data(uint32_t addr) {
+ if (addr % 4 != 0)
+ addr += 4 - (addr % 4);
+
+ // Load the alternative font metrics
+ CLCD::FontMetrics cyrillic_fm;
+ cyrillic_fm.ptr = addr + 148;
+ cyrillic_fm.format = L4;
+ cyrillic_fm.stride = 20;
+ cyrillic_fm.width = 40;
+ cyrillic_fm.height = 49;
+ LOOP_L_N(i, 127)
+ cyrillic_fm.char_widths[i] = 0;
+
+ // For cyrillic characters, copy the character widths from the widths tables
+ LOOP_L_N(i, NUM_ELEMENTS(cyrillic_font_widths)) {
+ cyrillic_fm.char_widths[i] = cyrillic_font_widths[i];
+ }
+ CLCD::mem_write_bulk(addr, &cyrillic_fm, 148);
+
+ // Decode the RLE data and load it into RAMG as a bitmap
+ uint32_t lastaddr = write_rle_data(addr + 148, cyrillic_font, sizeof(cyrillic_font));
+
+ bitmap_addr = addr;
+
+ return lastaddr;
+ }
+
+ /**
+ * Populates the bitmap handles for the custom into the display list.
+ * This function is called once at the start of each display list.
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ */
+
+ void FTDI::CyrillicCharSet::load_bitmaps(CommandProcessor& cmd) {
+ CLCD::FontMetrics cyrillic_fm;
+ cyrillic_fm.ptr = bitmap_addr + 148;
+ cyrillic_fm.format = L4;
+ cyrillic_fm.stride = 20;
+ cyrillic_fm.width = 40;
+ cyrillic_fm.height = 49;
+ set_font_bitmap(cmd, cyrillic_fm, cyrillic_font_handle);
+ }
+
+ /**
+ * Renders a character at location x and y. The x position is incremented
+ * by the width of the character.
+ *
+ * Parameters:
+ *
+ * cmd - If non-NULL the symbol is drawn to the screen.
+ * If NULL, only increment position for text measurement.
+ *
+ * x, y - The location at which to draw the character. On output,
+ * incremented to the location of the next character.
+ *
+ * fs - A scaling object used to scale the font. The display will
+ * already be configured to scale bitmaps, but positions
+ * must be scaled using fs.scale()
+ *
+ * c - The unicode code point to draw. If the renderer does not
+ * support the character, it should return false.
+ *
+ * Returns: Whether the character was supported.
+ */
+
+ bool FTDI::CyrillicCharSet::render_glyph(CommandProcessor* cmd, int &x, int &y, font_size_t fs, utf8_char_t c) {
+ // A supported character?
+ if ((c < UTF8('А') || c > UTF8('я')) && (c != UTF8('Ё')) && (c != UTF8('ё'))) return false;
+
+ uint8_t idx = (c == UTF8('Ё')) ? 64 :
+ (c == UTF8('ё')) ? 65 :
+ (c < UTF8('р')) ? c - UTF8('А') :
+ c - UTF8('р') + 48
+ ;
+
+ uint8_t width = cyrillic_font_widths[idx];
+
+ // Draw the character
+ if (cmd) ext_vertex2ii(*cmd, x, y, cyrillic_font_handle, idx);
+
+ // Increment X to the next character position
+ x += fs.scale(width);
+ return true;
+ }
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8 && TOUCH_UI_UTF8_WESTERN_CHARSET
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.h
new file mode 100644
index 0000000..63493b8
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.h
@@ -0,0 +1,32 @@
+/**********************
+ * cyrillic_char_set.h *
+ **********************/
+
+/****************************************************************************
+ * Written By Kirill Shashlov 2020 *
+ * Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+namespace FTDI {
+ class CyrillicCharSet {
+ private:
+ static uint32_t bitmap_addr;
+ public:
+ static uint32_t load_data(uint32_t addr);
+ static void load_bitmaps(CommandProcessor&);
+ static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t);
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set_bitmap_31.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set_bitmap_31.h
new file mode 100644
index 0000000..30b1f84
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set_bitmap_31.h
@@ -0,0 +1,2529 @@
+/********************************
+ * cyrillic_char_set_bitmap_31.h *
+ ********************************/
+
+/****************************************************************************
+ * Written By Kirill Shashlov 2020 *
+ * Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * Used GNU FreeFont FreeSans font (licensed under the GPL) *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+const uint8_t cyrillic_font_widths[] PROGMEM = {
+ 27, // А (0)
+ 26, // Б
+ 26, // В
+ 24, // Г
+ 33, // Д
+ 25, // Е
+ 37, // Ж
+ 26, // З
+
+ 28, // И (8)
+ 28, // Й
+ 26, // К
+ 25, // Л
+ 33, // М
+ 27, // Н
+ 31, // О
+ 27, // П
+
+ 26, // Р (16)
+ 29, // С
+ 28, // Т
+ 26, // У
+ 34, // Ф
+ 27, // Х
+ 30, // Ц
+ 23, // Ч
+
+ 32, // Ш (24)
+ 34, // Щ
+ 26, // Ь
+ 34, // Ы
+ 34, // Ъ
+ 28, // Э
+ 40, // Ю
+ 26, // Я
+
+ 22, // а (32)
+ 21, // б
+ 20, // в
+ 16, // г
+ 24, // д
+ 21, // е
+ 31, // ж
+ 19, // з
+
+ 21, // и (40)
+ 21, // й
+ 20, // к
+ 19, // л
+ 23, // м
+ 21, // н
+ 21, // о
+ 21, // п
+
+ 22, // р (48)
+ 20, // с
+ 17, // т
+ 19, // у
+ 34, // ф
+ 19, // х
+ 23, // ц
+ 19, // ч
+ 26, // ш
+ 28, // щ
+ 20, // ь
+ 26, // ы
+ 26, // ъ
+ 20, // э
+ 30, // ю
+ 20, // я
+
+ 26, // Ё
+ 21, // ё
+};
+
+
+/* This is a dump of "font_bitmaps/cyrillic_char_set_bitmap_31.png"
+ * using the tool "bitmap2cpp.py". The tool converts the image into
+ * 16-level grayscale and packs two pixels per byte. The resulting
+ * bytes are then RLE compressed to yield (count, byte) pairs.
+ */
+
+const unsigned char cyrillic_font[] PROGMEM = {
+ /* 0 */
+ 0xB9, 0x00, 0x01, 0x2F, 0x02, 0xFF, 0x01, 0x30, 0x10, 0x00, 0x01, 0x7F,
+ 0x02, 0xFF, 0x01, 0x90, 0x10, 0x00, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xE0,
+ 0x0F, 0x00, 0x01, 0x03, 0x03, 0xFF, 0x01, 0xF4, 0x0F, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xFB, 0x01, 0xFF, 0x01, 0xFA, 0x0F, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF1, 0x02, 0xFF, 0x0F, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0x90, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x50, 0x0E, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x40, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xB0, 0x0D, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xF1, 0x0D, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF7, 0x0D, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x01, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFC, 0x0D, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0x20, 0x0C, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x80, 0x0C, 0x00, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0x10, 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xD0, 0x0B, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFA, 0x03, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x01, 0xF3, 0x0B, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF5, 0x03, 0x00,
+ 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF9, 0x0B, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x01, 0xE0, 0x03, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xB4, 0x04, 0x44, 0x02, 0xFF, 0x01, 0x40,
+ 0x0A, 0x00, 0x01, 0xAF, 0x08, 0xFF, 0x01, 0xA0, 0x0A, 0x00, 0x09, 0xFF,
+ 0x01, 0xF0, 0x09, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x05, 0xEE, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xF5, 0x09, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF5,
+ 0x05, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFB, 0x09, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xF0, 0x05, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x90, 0x06, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x06, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xFE, 0x07, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xF2,
+ 0x07, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF8, 0x07, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF8, 0x07, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2,
+ 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xFD, 0x07, 0x00, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x30,
+ 0x06, 0x00, 0x01, 0x8D, 0x01, 0xDD, 0x01, 0x60, 0x08, 0x00, 0x01, 0xAD,
+ 0x01, 0xDD, 0x01, 0x70, 0xCE, 0x00,
+
+ /* 1 */
+ 0xB5, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xF4, 0x09, 0x00, 0x01, 0x1F,
+ 0x09, 0xFF, 0x01, 0xF4, 0x09, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xF4,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD5, 0x07, 0x55, 0x01, 0x51,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xFE,
+ 0x04, 0xEE, 0x01, 0xDB, 0x01, 0x84, 0x0B, 0x00, 0x01, 0x1F, 0x08, 0xFF,
+ 0x01, 0xE7, 0x0A, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xD2, 0x09, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD6, 0x04, 0x66, 0x01, 0x68, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x10, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x05, 0x00, 0x01, 0x04, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x90,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x06, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF5, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF9, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x06, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF4, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x06, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x05, 0x02, 0xFF, 0x01, 0x80,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE7, 0x04, 0x77, 0x01, 0x89,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFE, 0x09, 0x00, 0x01, 0x1F, 0x09, 0xFF,
+ 0x01, 0xE2, 0x09, 0x00, 0x01, 0x1F, 0x08, 0xFF, 0x01, 0xFB, 0x01, 0x10,
+ 0x09, 0x00, 0x01, 0x1D, 0x06, 0xDD, 0x01, 0xDC, 0x01, 0xB7, 0x01, 0x20,
+ 0xD1, 0x00,
+
+ /* 2 */
+ 0xB5, 0x00, 0x01, 0x1F, 0x06, 0xFF, 0x01, 0xEC, 0x01, 0x94, 0x0B, 0x00,
+ 0x01, 0x1F, 0x08, 0xFF, 0x01, 0xC3, 0x0A, 0x00, 0x01, 0x1F, 0x09, 0xFF,
+ 0x01, 0x40, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD6, 0x03, 0x66,
+ 0x01, 0x67, 0x01, 0x9D, 0x02, 0xFF, 0x01, 0xE1, 0x09, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x4E, 0x01, 0xFF, 0x01, 0xF9,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x04,
+ 0x02, 0xFF, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x20, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x06, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x30, 0x08, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0x20, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00,
+ 0x01, 0xCF, 0x01, 0xFF, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x05, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFA, 0x09, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xF2,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD2, 0x03, 0x22, 0x01, 0x23,
+ 0x01, 0x59, 0x02, 0xFF, 0x01, 0x50, 0x09, 0x00, 0x01, 0x1F, 0x08, 0xFF,
+ 0x01, 0xD3, 0x0A, 0x00, 0x01, 0x1F, 0x08, 0xFF, 0x01, 0xB3, 0x0A, 0x00,
+ 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xA0, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xD4, 0x04, 0x44, 0x01, 0x45, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x10, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00,
+ 0x01, 0x01, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF6, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x06, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF9,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xF7, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x06, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF5, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x05,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x90, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xE7, 0x04, 0x77, 0x01, 0x79, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x10, 0x08, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xE3, 0x09, 0x00,
+ 0x01, 0x1F, 0x08, 0xFF, 0x01, 0xFA, 0x01, 0x10, 0x09, 0x00, 0x01, 0x1D,
+ 0x07, 0xDD, 0x01, 0xB7, 0x01, 0x20, 0xD1, 0x00,
+
+ /* 3 */
+ 0xB5, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xF4, 0x09, 0x00, 0x01, 0x1F,
+ 0x09, 0xFF, 0x01, 0xF4, 0x09, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xF4,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD5, 0x07, 0x55, 0x01, 0x51,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1E,
+ 0x01, 0xEE, 0x01, 0xB0, 0xD8, 0x00,
+
+ /* 4 */
+ 0xB8, 0x00, 0x01, 0x08, 0x09, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08,
+ 0x09, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x09, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFA, 0x05, 0x66, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF6,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF6,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF6,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF5, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF5,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xF4, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF2,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xF0, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF0, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xA0, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x70, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x30,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xFE, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x08, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xF1,
+ 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0x22, 0x01, 0x28, 0x02, 0xFF, 0x01, 0xC7, 0x06, 0x77, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x52, 0x01, 0x22, 0x04, 0x00, 0x01, 0x0F, 0x0F, 0xFF,
+ 0x04, 0x00, 0x01, 0x0F, 0x0F, 0xFF, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xED, 0x0B, 0xDD, 0x01, 0xEF, 0x01, 0xFF, 0x04, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x04, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x50,
+ 0x0B, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x04, 0x00, 0x01, 0x06, 0x01, 0x66,
+ 0x01, 0x20, 0x0B, 0x00, 0x01, 0x26, 0x01, 0x66, 0x54, 0x00,
+
+ /* 5 */
+ 0xB5, 0x00, 0x01, 0x1F, 0x0A, 0xFF, 0x09, 0x00, 0x01, 0x1F, 0x0A, 0xFF,
+ 0x09, 0x00, 0x01, 0x1F, 0x0A, 0xFF, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xD6, 0x07, 0x66, 0x01, 0x65, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC1, 0x07, 0x11, 0x01, 0x10, 0x09, 0x00,
+ 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xF5, 0x09, 0x00, 0x01, 0x1F, 0x09, 0xFF,
+ 0x01, 0xF5, 0x09, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xF5, 0x09, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD4, 0x07, 0x44, 0x01, 0x41, 0x09, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE7, 0x08, 0x77, 0x01, 0x50, 0x08, 0x00,
+ 0x01, 0x1F, 0x0A, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x1F, 0x0A, 0xFF,
+ 0x01, 0xB0, 0x08, 0x00, 0x01, 0x1E, 0x0A, 0xEE, 0x01, 0xA0, 0xCF, 0x00,
+
+ /* 6 */
+ 0xB5, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xF3, 0x04, 0x00, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xE1,
+ 0x03, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10, 0x03, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00, 0x01, 0x0A, 0x02, 0xFF,
+ 0x01, 0x30, 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x03, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0xF5, 0x05, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF8,
+ 0x03, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x03,
+ 0x02, 0xFF, 0x01, 0x80, 0x05, 0x00, 0x01, 0x05, 0x02, 0xFF, 0x01, 0x50,
+ 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x1E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xF2,
+ 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFD,
+ 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x07, 0x00, 0x01, 0x01, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0xB0, 0x01, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90,
+ 0x01, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF4, 0x09, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xF7, 0x01, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90,
+ 0x01, 0x02, 0x02, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x05, 0x02, 0xFF,
+ 0x01, 0x40, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x1D, 0x01, 0xFF,
+ 0x01, 0xFA, 0x0B, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xE2, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0x90, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xC0, 0x0B, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x98,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10, 0x0C, 0x00, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xF3, 0x0D, 0x00,
+ 0x01, 0x2E, 0x05, 0xFF, 0x01, 0x60, 0x0D, 0x00, 0x01, 0x07, 0x04, 0xFF,
+ 0x01, 0xFC, 0x0E, 0x00, 0x01, 0x2E, 0x05, 0xFF, 0x01, 0x60, 0x0C, 0x00,
+ 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xF4, 0x0C, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x9A, 0x02, 0xFF, 0x01, 0x30, 0x0B, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xE2, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xE2, 0x0A, 0x00, 0x01, 0x09, 0x02, 0xFF,
+ 0x01, 0x30, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x10, 0x09, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xF4,
+ 0x01, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x01, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xC0, 0x08, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0x50,
+ 0x01, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xFB, 0x08, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF7,
+ 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00, 0x01, 0x04,
+ 0x02, 0xFF, 0x01, 0x90, 0x06, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x01, 0x80,
+ 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xF7, 0x06, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFA,
+ 0x03, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x08,
+ 0x02, 0xFF, 0x01, 0x50, 0x04, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x03, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xF4, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xFC, 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00,
+ 0x01, 0x0B, 0x02, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0xD1, 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xE1, 0x02, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x20, 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x10, 0x01, 0x00,
+ 0x01, 0x5D, 0x01, 0xDD, 0x01, 0xD3, 0x05, 0x00, 0x01, 0x3D, 0x01, 0xDD,
+ 0x01, 0x80, 0x04, 0x00, 0x01, 0x03, 0x02, 0xDD, 0x01, 0x90, 0xC9, 0x00,
+
+ /* 7 */
+ 0xA5, 0x00, 0x01, 0x45, 0x01, 0x67, 0x01, 0x65, 0x01, 0x20, 0x0E, 0x00,
+ 0x01, 0x06, 0x01, 0xCF, 0x03, 0xFF, 0x01, 0xFE, 0x01, 0x92, 0x0C, 0x00,
+ 0x01, 0x04, 0x01, 0xEF, 0x06, 0xFF, 0x01, 0x90, 0x0B, 0x00, 0x01, 0x6F,
+ 0x02, 0xFF, 0x01, 0xFD, 0x01, 0xCB, 0x01, 0xCF, 0x02, 0xFF, 0x01, 0xFC,
+ 0x0A, 0x00, 0x01, 0x04, 0x02, 0xFF, 0x01, 0xD6, 0x01, 0x10, 0x02, 0x00,
+ 0x01, 0x39, 0x02, 0xFF, 0x01, 0xA0, 0x09, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xF9, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF3, 0x09, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF9, 0x09, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x06, 0x00,
+ 0x01, 0xFF, 0x01, 0xFE, 0x09, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x07, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x09, 0x00, 0x01, 0xAC, 0x01, 0xCB, 0x07, 0x00,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x10, 0x10, 0x00, 0x01, 0x04, 0x02, 0xFF,
+ 0x11, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x01,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xF5, 0x10, 0x00, 0x01, 0x5D, 0x02, 0xFF,
+ 0x01, 0xA0, 0x0D, 0x00, 0x02, 0x99, 0x01, 0xBE, 0x02, 0xFF, 0x01, 0xF8,
+ 0x0E, 0x00, 0x05, 0xFF, 0x01, 0x40, 0x0E, 0x00, 0x05, 0xFF, 0x01, 0xF9,
+ 0x0E, 0x00, 0x02, 0xBB, 0x01, 0xCD, 0x03, 0xFF, 0x01, 0xD1, 0x10, 0x00,
+ 0x01, 0x16, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFC, 0x11, 0x00, 0x01, 0x0A,
+ 0x02, 0xFF, 0x01, 0x60, 0x11, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xC0,
+ 0x07, 0x00, 0x01, 0x07, 0x01, 0x99, 0x01, 0x80, 0x07, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xF0, 0x07, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF0,
+ 0x07, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF1, 0x07, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xF2, 0x07, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF1,
+ 0x07, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8, 0x07, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xE0, 0x07, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x20,
+ 0x06, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0xD2, 0x05, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x01, 0x30,
+ 0x08, 0x00, 0x01, 0x1E, 0x02, 0xFF, 0x01, 0x81, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xFA, 0x09, 0x00, 0x01, 0x03, 0x01, 0xEF,
+ 0x02, 0xFF, 0x01, 0xDA, 0x01, 0x98, 0x01, 0x9A, 0x01, 0xDF, 0x02, 0xFF,
+ 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x2D, 0x07, 0xFF, 0x01, 0xFA, 0x0C, 0x00,
+ 0x01, 0x6D, 0x05, 0xFF, 0x01, 0xFB, 0x01, 0x30, 0x0D, 0x00, 0x01, 0x27,
+ 0x01, 0x9B, 0x01, 0xCD, 0x01, 0xBA, 0x01, 0x95, 0x01, 0x10, 0xBE, 0x00,
+
+ /* 8 */
+ 0xB5, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x07, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x06, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x90, 0x06, 0x00, 0x01, 0x2F, 0x02, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x06, 0x00, 0x01, 0xCF,
+ 0x02, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x05, 0x00, 0x01, 0x06, 0x03, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x90, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x05, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xFA, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x1E, 0x01, 0xFF,
+ 0x01, 0xE1, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x60,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x70, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x02, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFD, 0x02, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x02, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF3, 0x02, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x80, 0x02, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFD, 0x03, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFE, 0x01, 0x10, 0x03, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF5, 0x04, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xB0, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x10, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x99, 0x01, 0xFF, 0x01, 0xF6,
+ 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x03, 0xFF, 0x01, 0x20,
+ 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F,
+ 0x02, 0xFF, 0x01, 0xF7, 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x02, 0xFF, 0x01, 0xD0, 0x06, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x02, 0xFF, 0x01, 0x30,
+ 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1E,
+ 0x01, 0xEE, 0x01, 0xE8, 0x07, 0x00, 0x01, 0x0E, 0x01, 0xEE, 0x01, 0xA0,
+ 0xCE, 0x00,
+
+ /* 9 */
+ 0x2C, 0x00, 0x01, 0x7F, 0x01, 0xF1, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xE0,
+ 0x0D, 0x00, 0x01, 0x5F, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xB0, 0x0D, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xB6, 0x01, 0x45,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x50, 0x0D, 0x00, 0x01, 0x05, 0x04, 0xFF,
+ 0x01, 0xFB, 0x0F, 0x00, 0x01, 0x5E, 0x03, 0xFF, 0x01, 0x90, 0x10, 0x00,
+ 0x01, 0x46, 0x01, 0x87, 0x01, 0x51, 0x20, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x07, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x06, 0x00, 0x01, 0x07, 0x02, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x06, 0x00,
+ 0x01, 0x2F, 0x02, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x06, 0x00, 0x01, 0xBF, 0x02, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x05, 0x00, 0x01, 0x06, 0x03, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x05, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x05, 0x00, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x04, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFA, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xE1, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x60, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00, 0x01, 0x04,
+ 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x70, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xFD, 0x02, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF3, 0x02, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0x80, 0x02, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xFD, 0x03, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x01, 0x01, 0xEF,
+ 0x01, 0xFE, 0x01, 0x10, 0x03, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x0A, 0x01, 0xFF,
+ 0x01, 0xF5, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x90, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x10, 0x04, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x99, 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0xC0, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x1F, 0x03, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x02, 0xFF, 0x01, 0xF7, 0x06, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x02, 0xFF,
+ 0x01, 0xD0, 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x1F, 0x02, 0xFF, 0x01, 0x30, 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xE8, 0x07, 0x00,
+ 0x01, 0x0E, 0x01, 0xEE, 0x01, 0xA0, 0xCE, 0x00,
+
+ /* 10 */
+ 0xB5, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x1D,
+ 0x01, 0xFF, 0x01, 0xFA, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x04, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xA0, 0x09, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x04, 0x00, 0x01, 0x1D, 0x01, 0xFF,
+ 0x01, 0xF9, 0x0A, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x03, 0x00,
+ 0x01, 0x01, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x90, 0x0A, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x2D, 0x01, 0xFF, 0x01, 0xF9,
+ 0x0B, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x90, 0x0B, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x02, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xF8, 0x0C, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x01, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x80, 0x0C, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x01, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xF8, 0x0D, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x80,
+ 0x0D, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x01, 0x2E, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0E, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC3, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x70, 0x0E, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xEE,
+ 0x01, 0xFF, 0x01, 0xF7, 0x0F, 0x00, 0x01, 0x1F, 0x03, 0xFF, 0x01, 0x70,
+ 0x0F, 0x00, 0x01, 0x1F, 0x03, 0xFF, 0x01, 0x20, 0x0F, 0x00, 0x01, 0x1F,
+ 0x03, 0xFF, 0x01, 0xE2, 0x0F, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xDD,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x0E, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC1, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xE2, 0x0E, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20,
+ 0x0D, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x01, 0x01, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0xE2, 0x0D, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x01, 0x00, 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x0C, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x01, 0x00, 0x01, 0x01, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0xE2, 0x0C, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x02, 0x00, 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x0B, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0x01, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0xE2, 0x0B, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x03, 0x00, 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x30, 0x0A, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xE3, 0x0A, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x04, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x30, 0x09, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x04, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xE3, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x05, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x30, 0x08, 0x00,
+ 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xB0, 0x05, 0x00, 0x01, 0x02, 0x01, 0xDE,
+ 0x01, 0xEE, 0x01, 0xD2, 0xCF, 0x00,
+
+ /* 11 */
+ 0xB6, 0x00, 0x01, 0x08, 0x09, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08,
+ 0x09, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x09, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFA, 0x05, 0x66, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF6,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF6,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF6,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF5, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF4,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF4, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF1,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF0, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xE0, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0x90, 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x60, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x20,
+ 0x05, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x08, 0x00, 0x01, 0x01,
+ 0x01, 0xFF, 0x01, 0xFE, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x08, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF9, 0x06, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x30, 0x08, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF2,
+ 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x07, 0x00, 0x01, 0x1A,
+ 0x02, 0xFF, 0x01, 0xA0, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30,
+ 0x07, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x07, 0x00, 0x01, 0x2F, 0x01, 0xFF,
+ 0x01, 0xF4, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x07, 0x00,
+ 0x01, 0x2F, 0x01, 0xFB, 0x01, 0x20, 0x07, 0x00, 0x01, 0xAE, 0x01, 0xEE,
+ 0x01, 0x30, 0x07, 0x00, 0x01, 0x03, 0x01, 0x10, 0xC6, 0x00,
+
+ /* 12 */
+ 0xB5, 0x00, 0x01, 0x1E, 0x02, 0xEE, 0x01, 0x70, 0x08, 0x00, 0x02, 0xEE,
+ 0x01, 0xE7, 0x05, 0x00, 0x01, 0x1F, 0x02, 0xFF, 0x01, 0xC0, 0x07, 0x00,
+ 0x01, 0x05, 0x02, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x02, 0xFF,
+ 0x01, 0xF2, 0x07, 0x00, 0x01, 0x0B, 0x02, 0xFF, 0x01, 0xF8, 0x05, 0x00,
+ 0x01, 0x1F, 0x02, 0xFF, 0x01, 0xF7, 0x07, 0x00, 0x01, 0x1F, 0x02, 0xFF,
+ 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x02, 0xFF, 0x01, 0xFD, 0x07, 0x00,
+ 0x01, 0x6F, 0x02, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x30, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFC,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x9D,
+ 0x01, 0xFF, 0x01, 0x80, 0x05, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF7,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x98,
+ 0x01, 0xFF, 0x01, 0xE0, 0x05, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xE2,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x92,
+ 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x92,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x01, 0xDF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x42,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x01, 0x7F, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFE, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x40, 0x04, 0x00, 0x01, 0xCF, 0x01, 0xF9,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0x90, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xE0,
+ 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x01,
+ 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0x80,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0xCF, 0x01, 0xFA, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x30, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00, 0x01, 0x6F, 0x01, 0xFF,
+ 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFD, 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x50, 0x02, 0x00, 0x01, 0xCF, 0x01, 0xF8,
+ 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xA0,
+ 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x01, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x01, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xD0, 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0xFF,
+ 0x01, 0xF6, 0x01, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x80, 0x01, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x90, 0x02, 0x00, 0x01, 0xAF, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x20, 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0x10, 0x01, 0x7F, 0x01, 0xFD, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x02, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x60, 0x01, 0xDF, 0x01, 0xF7,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xC2,
+ 0x01, 0xFF, 0x01, 0xF2, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00, 0x01, 0x04,
+ 0x01, 0xFF, 0x01, 0xFA, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x03, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0x70, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x03, 0x00, 0x01, 0x9F, 0x02, 0xFF, 0x01, 0x20, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x03, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0x80,
+ 0x03, 0x00, 0x01, 0x0D, 0x01, 0xEE, 0x01, 0xE6, 0x03, 0x00, 0x01, 0x02,
+ 0x01, 0xEE, 0x01, 0xE7, 0xCC, 0x00,
+
+ /* 13 */
+ 0xB5, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x0B, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x0B, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x0B, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD4,
+ 0x07, 0x44, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1E,
+ 0x01, 0xEE, 0x01, 0xB0, 0x07, 0x00, 0x01, 0x8E, 0x01, 0xEE, 0x01, 0x40,
+ 0xCE, 0x00,
+
+ /* 14 */
+ 0xA6, 0x00, 0x01, 0x13, 0x01, 0x56, 0x01, 0x64, 0x01, 0x31, 0x0E, 0x00,
+ 0x01, 0x02, 0x01, 0x8D, 0x04, 0xFF, 0x01, 0xC7, 0x01, 0x10, 0x0B, 0x00,
+ 0x01, 0x01, 0x01, 0x9F, 0x06, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0x3E,
+ 0x08, 0xFF, 0x01, 0xD2, 0x09, 0x00, 0x01, 0x04, 0x02, 0xFF, 0x01, 0xFC,
+ 0x01, 0x72, 0x01, 0x00, 0x01, 0x01, 0x01, 0x38, 0x01, 0xDF, 0x02, 0xFF,
+ 0x01, 0x30, 0x08, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x50,
+ 0x04, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xE2, 0x07, 0x00, 0x01, 0x01,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xD1, 0x06, 0x00, 0x01, 0x2E, 0x01, 0xFF,
+ 0x01, 0xFD, 0x07, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10,
+ 0x06, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0x60, 0x06, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xF4, 0x08, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xE0,
+ 0x06, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF5, 0x06, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x30,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xFD, 0x0A, 0x00, 0x02, 0xFF, 0x05, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF9, 0x0A, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x30,
+ 0x04, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF5, 0x0A, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x50, 0x04, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF4,
+ 0x0A, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x70, 0x04, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xF2, 0x0A, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x80,
+ 0x04, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF2, 0x0A, 0x00, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF3,
+ 0x0A, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x80, 0x04, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF4, 0x0A, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x60,
+ 0x04, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7, 0x0A, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x50, 0x04, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFB,
+ 0x0A, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x10, 0x05, 0x00, 0x02, 0xFF,
+ 0x01, 0x10, 0x08, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFD, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xF8, 0x06, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xE1, 0x08, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xF1, 0x06, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xFA, 0x08, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xA0, 0x06, 0x00,
+ 0x01, 0x04, 0x02, 0xFF, 0x01, 0x80, 0x06, 0x00, 0x01, 0x0A, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x10, 0x07, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0x01, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xF5, 0x08, 0x00,
+ 0x01, 0x0B, 0x02, 0xFF, 0x01, 0xE6, 0x01, 0x10, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0x8F, 0x02, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0xAF, 0x02, 0xFF,
+ 0x01, 0xFC, 0x01, 0xA8, 0x01, 0x8A, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xF6,
+ 0x0A, 0x00, 0x01, 0x06, 0x01, 0xEF, 0x06, 0xFF, 0x01, 0xFD, 0x01, 0x40,
+ 0x0B, 0x00, 0x01, 0x18, 0x01, 0xEF, 0x04, 0xFF, 0x01, 0xFD, 0x01, 0x60,
+ 0x0D, 0x00, 0x01, 0x03, 0x01, 0x7A, 0x01, 0xCD, 0x01, 0xDC, 0x01, 0xA7,
+ 0x01, 0x30, 0xBD, 0x00,
+
+ /* 15 */
+ 0xB5, 0x00, 0x01, 0x1F, 0x0B, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x0B, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x0B, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE6, 0x07, 0x66, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1E,
+ 0x01, 0xEE, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9E, 0x01, 0xEE, 0x01, 0x40,
+ 0xCE, 0x00,
+
+ /* 16 */
+ 0xB5, 0x00, 0x01, 0x1E, 0x06, 0xEE, 0x01, 0xEC, 0x01, 0x95, 0x0B, 0x00,
+ 0x01, 0x1F, 0x08, 0xFF, 0x01, 0xE5, 0x0A, 0x00, 0x01, 0x1F, 0x09, 0xFF,
+ 0x01, 0x80, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD6, 0x03, 0x66,
+ 0x01, 0x67, 0x01, 0x9D, 0x02, 0xFF, 0x01, 0xF5, 0x09, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x4E, 0x01, 0xFF, 0x01, 0xFE,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x03,
+ 0x02, 0xFF, 0x01, 0x50, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x06, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x90, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x06, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xC0, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x05, 0x00, 0x01, 0x1B, 0x02, 0xFF, 0x01, 0x10, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC1, 0x03, 0x11, 0x01, 0x12, 0x01, 0x48, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xF9, 0x09, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xC0,
+ 0x09, 0x00, 0x01, 0x1F, 0x08, 0xFF, 0x01, 0xFB, 0x01, 0x10, 0x09, 0x00,
+ 0x01, 0x1F, 0x07, 0xFF, 0x01, 0xFB, 0x01, 0x40, 0x0A, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD4, 0x04, 0x44, 0x01, 0x32, 0x0C, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xB0, 0xD8, 0x00,
+
+ /* 17 */
+ 0xA6, 0x00, 0x01, 0x35, 0x01, 0x66, 0x01, 0x54, 0x01, 0x10, 0x0E, 0x00,
+ 0x01, 0x06, 0x01, 0xCF, 0x03, 0xFF, 0x01, 0xFD, 0x01, 0x71, 0x0C, 0x00,
+ 0x01, 0x05, 0x01, 0xEF, 0x06, 0xFF, 0x01, 0x60, 0x0B, 0x00, 0x01, 0xAF,
+ 0x07, 0xFF, 0x01, 0xF8, 0x0A, 0x00, 0x01, 0x0A, 0x02, 0xFF, 0x01, 0xD7,
+ 0x01, 0x20, 0x01, 0x00, 0x01, 0x03, 0x01, 0x9F, 0x02, 0xFF, 0x01, 0x70,
+ 0x09, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x01,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xF2, 0x08, 0x00, 0x01, 0x02, 0x02, 0xFF,
+ 0x01, 0x60, 0x05, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFA, 0x08, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0x02, 0x02, 0xFF,
+ 0x01, 0x10, 0x07, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x60, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF,
+ 0x01, 0x60, 0x07, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x10, 0x07, 0x00, 0x01, 0x05, 0x01, 0x55,
+ 0x01, 0x40, 0x06, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFB, 0x11, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8, 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xF5, 0x11, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF3, 0x11, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF2, 0x11, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0xF2, 0x11, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF3, 0x11, 0x00,
+ 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF4, 0x11, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF6, 0x11, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFA, 0x08, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x06, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xFE, 0x08, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF3, 0x07, 0x00,
+ 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xF0, 0x07, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xB0, 0x07, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xB0, 0x07, 0x00, 0x01, 0x1E, 0x01, 0xFF,
+ 0x01, 0xF5, 0x07, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x60, 0x07, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x05, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10, 0x08, 0x00, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0xE3, 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF7, 0x09, 0x00,
+ 0x01, 0x3F, 0x02, 0xFF, 0x01, 0x92, 0x03, 0x00, 0x01, 0x29, 0x02, 0xFF,
+ 0x01, 0xC0, 0x09, 0x00, 0x01, 0x04, 0x03, 0xFF, 0x01, 0xDA, 0x01, 0x88,
+ 0x01, 0x9C, 0x02, 0xFF, 0x01, 0xFE, 0x01, 0x10, 0x0A, 0x00, 0x01, 0x3D,
+ 0x07, 0xFF, 0x01, 0xC1, 0x0C, 0x00, 0x01, 0x7E, 0x05, 0xFF, 0x01, 0xD6,
+ 0x0E, 0x00, 0x01, 0x37, 0x01, 0xAC, 0x01, 0xDD, 0x01, 0xCA, 0x01, 0x73,
+ 0xBE, 0x00,
+
+ /* 18 */
+ 0xB4, 0x00, 0x01, 0x2F, 0x0B, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x2F,
+ 0x0B, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x2F, 0x0B, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x16, 0x04, 0x66, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xD6,
+ 0x04, 0x66, 0x01, 0x40, 0x0C, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x2E, 0x01, 0xEE, 0x01, 0xA0, 0xD4, 0x00,
+
+ /* 19 */
+ 0xB4, 0x00, 0x01, 0x8E, 0x01, 0xEE, 0x01, 0xE2, 0x07, 0x00, 0x01, 0xDE,
+ 0x01, 0xEE, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xFA,
+ 0x06, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0x30, 0x07, 0x00, 0x01, 0x08,
+ 0x02, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xFA,
+ 0x08, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x90, 0x05, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xF2, 0x09, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xF2,
+ 0x05, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xA0, 0x09, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0x20,
+ 0x09, 0x00, 0x01, 0x08, 0x02, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0xFA, 0x0A, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xF2, 0x03, 0x00, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0x90, 0x0B, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x05, 0x02, 0xFF, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x07, 0x02, 0xFF,
+ 0x01, 0x20, 0x01, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF9, 0x0D, 0x00,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x90, 0x01, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0xF1, 0x0D, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x80, 0x0D, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x01, 0xF9, 0x01, 0x05, 0x02, 0xFF, 0x01, 0x10, 0x0D, 0x00, 0x01, 0x07,
+ 0x02, 0xFF, 0x01, 0x2D, 0x01, 0xFF, 0x01, 0xF8, 0x0F, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xF1, 0x0F, 0x00, 0x01, 0x7F,
+ 0x03, 0xFF, 0x01, 0x80, 0x0F, 0x00, 0x01, 0x0E, 0x02, 0xFF, 0x01, 0xFE,
+ 0x01, 0x10, 0x0F, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0xF7, 0x11, 0x00,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xE0, 0x10, 0x00, 0x01, 0x01, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x70, 0x10, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFE,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF6, 0x11, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0xE0, 0x10, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0x60,
+ 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFE, 0x11, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xF6, 0x11, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xD0,
+ 0x10, 0x00, 0x01, 0x05, 0x02, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xEE, 0x01, 0xEC, 0xD7, 0x00,
+
+ /* 20 */
+ 0xBB, 0x00, 0x01, 0x0B, 0x01, 0xEE, 0x01, 0xE2, 0x11, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF2, 0x11, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF2,
+ 0x10, 0x00, 0x01, 0x01, 0x01, 0x2D, 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x10,
+ 0x0D, 0x00, 0x01, 0x48, 0x01, 0xCE, 0x05, 0xFF, 0x01, 0xFD, 0x01, 0x96,
+ 0x01, 0x10, 0x09, 0x00, 0x01, 0x7D, 0x09, 0xFF, 0x01, 0xFA, 0x01, 0x20,
+ 0x07, 0x00, 0x01, 0x2D, 0x0B, 0xFF, 0x01, 0xF6, 0x06, 0x00, 0x01, 0x03,
+ 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x75, 0x01, 0x4D, 0x01, 0xFF,
+ 0x01, 0xF6, 0x01, 0x56, 0x01, 0x9D, 0x03, 0xFF, 0x01, 0x80, 0x05, 0x00,
+ 0x01, 0x1E, 0x02, 0xFF, 0x01, 0xE6, 0x02, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x02, 0x00, 0x01, 0x3B, 0x02, 0xFF, 0x01, 0xF5, 0x05, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x10, 0x02, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF2, 0x03, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xFE,
+ 0x05, 0x00, 0x02, 0xFF, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x03, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0x50, 0x03, 0x00,
+ 0x01, 0x05, 0x02, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFC, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xE0, 0x03, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xF0, 0x03, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF1, 0x03, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF1, 0x03, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xF0, 0x03, 0x00,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFC, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xE0, 0x03, 0x00,
+ 0x01, 0x05, 0x02, 0xFF, 0x01, 0x30, 0x03, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xB0, 0x04, 0x00,
+ 0x02, 0xFF, 0x01, 0xD1, 0x03, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF2,
+ 0x03, 0x00, 0x01, 0x08, 0x02, 0xFF, 0x01, 0x60, 0x04, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x10, 0x02, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xFE, 0x05, 0x00,
+ 0x01, 0x1E, 0x02, 0xFF, 0x01, 0xF7, 0x01, 0x10, 0x01, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF2, 0x02, 0x00, 0x01, 0x4C, 0x02, 0xFF, 0x01, 0xF6,
+ 0x05, 0x00, 0x01, 0x04, 0x03, 0xFF, 0x01, 0xFB, 0x01, 0x86, 0x01, 0x5D,
+ 0x01, 0xFF, 0x01, 0xF6, 0x01, 0x67, 0x01, 0xAE, 0x03, 0xFF, 0x01, 0xA0,
+ 0x06, 0x00, 0x01, 0x4E, 0x0B, 0xFF, 0x01, 0xF8, 0x07, 0x00, 0x01, 0x01,
+ 0x01, 0x8E, 0x09, 0xFF, 0x01, 0xFB, 0x01, 0x30, 0x09, 0x00, 0x01, 0x48,
+ 0x01, 0xBE, 0x05, 0xFF, 0x01, 0xED, 0x01, 0xA6, 0x01, 0x10, 0x0D, 0x00,
+ 0x01, 0x1C, 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x10, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF2, 0x11, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF2,
+ 0x11, 0x00, 0x01, 0x0B, 0x01, 0xEE, 0x01, 0xE2, 0xD2, 0x00,
+
+ /* 21 */
+ 0xB4, 0x00, 0x01, 0x0B, 0x01, 0xEE, 0x01, 0xEC, 0x07, 0x00, 0x01, 0x2E,
+ 0x01, 0xEE, 0x01, 0xE7, 0x07, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0x80,
+ 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xC0, 0x08, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0x20,
+ 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFD, 0x05, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xF6, 0x09, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0x80, 0x04, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xB0, 0x0A, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF3, 0x03, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x10, 0x0A, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xFD,
+ 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xF5, 0x0B, 0x00, 0x01, 0x01,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x80, 0x02, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x90, 0x0C, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFD, 0x0D, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xF3, 0x0E, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x80, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x70,
+ 0x0E, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0xFF, 0x01, 0xFC,
+ 0x0F, 0x00, 0x01, 0x08, 0x03, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0xCF,
+ 0x02, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xFC,
+ 0x11, 0x00, 0x01, 0xAF, 0x02, 0xFF, 0x01, 0x30, 0x0F, 0x00, 0x01, 0x05,
+ 0x03, 0xFF, 0x01, 0xD0, 0x0F, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0xFF, 0x01, 0xF9, 0x0F, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x91,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x50, 0x0D, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xE1, 0x0D, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0xFB, 0x0D, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x80, 0x01, 0x00,
+ 0x01, 0x01, 0x02, 0xFF, 0x01, 0x60, 0x0B, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xFD, 0x03, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF3, 0x03, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0xFC, 0x0A, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x80,
+ 0x03, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xFD, 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF4,
+ 0x09, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10, 0x07, 0x00, 0x01, 0x02, 0x02, 0xFF,
+ 0x01, 0x80, 0x05, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFD, 0x07, 0x00, 0x01, 0x6F, 0x01, 0xFF,
+ 0x01, 0xF5, 0x07, 0x00, 0x01, 0x6E, 0x01, 0xEE, 0x01, 0xE3, 0x07, 0x00,
+ 0x01, 0x0B, 0x01, 0xEE, 0x01, 0xED, 0x01, 0x10, 0xCE, 0x00,
+
+ /* 22 */
+ 0xB5, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x9E,
+ 0x01, 0xEE, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40,
+ 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x07, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xE6, 0x07, 0x66, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x51,
+ 0x01, 0x10, 0x06, 0x00, 0x01, 0x1F, 0x0C, 0xFF, 0x01, 0xF1, 0x06, 0x00,
+ 0x01, 0x1F, 0x0C, 0xFF, 0x01, 0xF1, 0x06, 0x00, 0x01, 0x1F, 0x0C, 0xFF,
+ 0x01, 0xF1, 0x11, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF1, 0x11, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF1, 0x11, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF1, 0x11, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF1, 0x11, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF1, 0x11, 0x00, 0x01, 0x01, 0x01, 0x77,
+ 0x01, 0x70, 0x55, 0x00,
+
+ /* 23 */
+ 0xB4, 0x00, 0x01, 0x04, 0x01, 0xEE, 0x01, 0xE8, 0x06, 0x00, 0x01, 0xBE,
+ 0x01, 0xEE, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8,
+ 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8,
+ 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8,
+ 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8,
+ 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x08, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x10, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFA,
+ 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x09, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x09, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0xBA, 0x04, 0xAA,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x10, 0x09, 0x00, 0x01, 0x0B, 0x09, 0xFF,
+ 0x01, 0x10, 0x0A, 0x00, 0x01, 0x8F, 0x08, 0xFF, 0x01, 0x10, 0x0A, 0x00,
+ 0x01, 0x01, 0x01, 0x69, 0x05, 0xAA, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x10,
+ 0x11, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x11, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x10, 0x11, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x11, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x11, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x10, 0x11, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x11, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x11, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x10, 0x11, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x11, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x11, 0x00, 0x01, 0xBE,
+ 0x01, 0xEE, 0x01, 0x10, 0xD0, 0x00,
+
+ /* 24 */
+ 0xB5, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x1E,
+ 0x01, 0xEE, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xC0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE6, 0x03, 0x66, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0xE6, 0x03, 0x66, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x0D, 0xFF, 0x01, 0xD0, 0x05, 0x00, 0x01, 0x1F,
+ 0x0D, 0xFF, 0x01, 0xD0, 0x05, 0x00, 0x01, 0x1F, 0x0D, 0xFF, 0x01, 0xC0,
+ 0xCC, 0x00,
+
+ /* 25 */
+ 0xB5, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x1E,
+ 0x01, 0xEE, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xC0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE6, 0x03, 0x66, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0xE6, 0x03, 0x66, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xD1,
+ 0x01, 0x10, 0x04, 0x00, 0x01, 0x1F, 0x0E, 0xFF, 0x01, 0xFA, 0x04, 0x00,
+ 0x01, 0x1F, 0x0E, 0xFF, 0x01, 0xFA, 0x04, 0x00, 0x01, 0x1F, 0x0E, 0xFF,
+ 0x01, 0xFA, 0x12, 0x00, 0x01, 0xBF, 0x01, 0xFA, 0x12, 0x00, 0x01, 0xBF,
+ 0x01, 0xFA, 0x12, 0x00, 0x01, 0xBF, 0x01, 0xFA, 0x12, 0x00, 0x01, 0xBF,
+ 0x01, 0xFA, 0x12, 0x00, 0x01, 0xBF, 0x01, 0xFA, 0x12, 0x00, 0x01, 0x57,
+ 0x01, 0x74, 0x53, 0x00,
+
+ /* 26 */
+ 0xB5, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE8,
+ 0x03, 0x88, 0x01, 0x76, 0x01, 0x53, 0x0C, 0x00, 0x01, 0x1F, 0x07, 0xFF,
+ 0x01, 0xFB, 0x01, 0x50, 0x0A, 0x00, 0x01, 0x1F, 0x08, 0xFF, 0x01, 0xFD,
+ 0x01, 0x30, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xFC, 0x03, 0xCC,
+ 0x01, 0xCD, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xF5, 0x09, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x04, 0x00, 0x01, 0x01, 0x01, 0x7E, 0x02, 0xFF,
+ 0x01, 0x20, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xF6, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x06, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF9,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x06, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF6, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2,
+ 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0xC0, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x05, 0x00, 0x01, 0x1A, 0x02, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD6, 0x04, 0x66, 0x01, 0x7B, 0x02, 0xFF, 0x01, 0xF9,
+ 0x09, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xA0, 0x09, 0x00, 0x01, 0x1F,
+ 0x08, 0xFF, 0x01, 0xE6, 0x0A, 0x00, 0x01, 0x1E, 0x06, 0xEE, 0x01, 0xED,
+ 0x01, 0xA5, 0xD2, 0x00,
+
+ /* 27 */
+ 0xB5, 0x00, 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xB0, 0x0A, 0x00, 0x01, 0x3E,
+ 0x01, 0xEE, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xE8, 0x03, 0x88, 0x01, 0x76, 0x01, 0x52, 0x05, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F, 0x07, 0xFF,
+ 0x01, 0xFB, 0x01, 0x50, 0x03, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x04, 0x00, 0x01, 0x1F, 0x08, 0xFF, 0x01, 0xFD, 0x01, 0x30, 0x02, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xFD, 0x04, 0xDD, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xF5, 0x02, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x04, 0x00, 0x01, 0x01, 0x01, 0x7E, 0x02, 0xFF, 0x01, 0x20,
+ 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x02, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x3F, 0x01, 0xFF,
+ 0x01, 0xF1, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0xF6, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF8, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x04, 0x01, 0xFF,
+ 0x01, 0xF9, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xF8, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xF6, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x01, 0xF2, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x06, 0x00, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0xC0, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x1A, 0x02, 0xFF,
+ 0x01, 0x40, 0x01, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD6, 0x04, 0x66, 0x01, 0x7A, 0x02, 0xFF,
+ 0x01, 0xF9, 0x02, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00,
+ 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xA0, 0x02, 0x00, 0x01, 0x3F, 0x01, 0xFF,
+ 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1F, 0x08, 0xFF, 0x01, 0xE6, 0x03, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x1E, 0x06, 0xEE,
+ 0x01, 0xED, 0x01, 0xA5, 0x04, 0x00, 0x01, 0x3E, 0x01, 0xEE, 0x01, 0xA0,
+ 0xCB, 0x00,
+
+ /* 28 */
+ 0xB4, 0x00, 0x01, 0x2E, 0x06, 0xEE, 0x01, 0x50, 0x0C, 0x00, 0x01, 0x2F,
+ 0x06, 0xFF, 0x01, 0x50, 0x0C, 0x00, 0x01, 0x2F, 0x06, 0xFF, 0x01, 0x50,
+ 0x0C, 0x00, 0x01, 0x17, 0x04, 0x77, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50,
+ 0x11, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50,
+ 0x11, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50,
+ 0x11, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50, 0x11, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0xB8, 0x03, 0x88, 0x01, 0x76, 0x01, 0x41, 0x0C, 0x00,
+ 0x01, 0x8F, 0x07, 0xFF, 0x01, 0xE8, 0x01, 0x20, 0x0A, 0x00, 0x01, 0x8F,
+ 0x08, 0xFF, 0x01, 0xF9, 0x0A, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xED,
+ 0x04, 0xDD, 0x03, 0xFF, 0x01, 0xC0, 0x09, 0x00, 0x01, 0x8F, 0x01, 0xFF,
+ 0x01, 0x50, 0x04, 0x00, 0x01, 0x03, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xFB,
+ 0x09, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50, 0x05, 0x00, 0x01, 0x07,
+ 0x02, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50,
+ 0x06, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xE0,
+ 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50,
+ 0x06, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50,
+ 0x06, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x50, 0x05, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0x50,
+ 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50, 0x05, 0x00, 0x01, 0x4E,
+ 0x01, 0xFF, 0x01, 0xFD, 0x09, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x96,
+ 0x04, 0x66, 0x01, 0x8D, 0x02, 0xFF, 0x01, 0xF3, 0x09, 0x00, 0x01, 0x8F,
+ 0x08, 0xFF, 0x01, 0xFE, 0x01, 0x40, 0x09, 0x00, 0x01, 0x8F, 0x08, 0xFF,
+ 0x01, 0xB2, 0x0A, 0x00, 0x01, 0x7E, 0x06, 0xEE, 0x01, 0xEC, 0x01, 0x83,
+ 0xCE, 0x00,
+
+ /* 29 */
+ 0xA5, 0x00, 0x01, 0x14, 0x01, 0x56, 0x01, 0x54, 0x01, 0x20, 0x0E, 0x00,
+ 0x01, 0x02, 0x01, 0x8E, 0x03, 0xFF, 0x01, 0xFE, 0x01, 0xA4, 0x0D, 0x00,
+ 0x01, 0x8F, 0x06, 0xFF, 0x01, 0xC2, 0x0B, 0x00, 0x01, 0x0C, 0x08, 0xFF,
+ 0x01, 0x50, 0x0A, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x73,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0x49, 0x02, 0xFF, 0x01, 0xF6, 0x09, 0x00,
+ 0x01, 0x05, 0x02, 0xFF, 0x01, 0x80, 0x04, 0x00, 0x01, 0x2C, 0x02, 0xFF,
+ 0x01, 0x30, 0x08, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0xD0, 0x06, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF6, 0x08, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x60, 0x06, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xFE, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x10, 0x07, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x55, 0x01, 0x54,
+ 0x08, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x90, 0x11, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF1,
+ 0x11, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF4, 0x0A, 0x00, 0x01, 0xBF,
+ 0x08, 0xFF, 0x01, 0xF5, 0x0A, 0x00, 0x01, 0xBF, 0x08, 0xFF, 0x01, 0xF6,
+ 0x0A, 0x00, 0x01, 0xBF, 0x08, 0xFF, 0x01, 0xF7, 0x0A, 0x00, 0x01, 0x35,
+ 0x06, 0x55, 0x01, 0x5A, 0x01, 0xFF, 0x01, 0xF6, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xF5, 0x11, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF3,
+ 0x06, 0x00, 0x01, 0x09, 0x01, 0xEE, 0x01, 0xE5, 0x08, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF0, 0x06, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF8,
+ 0x08, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xD0, 0x06, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xFD, 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x70,
+ 0x06, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x90,
+ 0x06, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFB, 0x08, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0xF3, 0x06, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF3,
+ 0x08, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x04, 0x00,
+ 0x01, 0x06, 0x02, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x03, 0x02, 0xFF,
+ 0x01, 0xE6, 0x03, 0x00, 0x01, 0x03, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xFD,
+ 0x0A, 0x00, 0x01, 0x5F, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x87, 0x01, 0x8A,
+ 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xD1, 0x0A, 0x00, 0x01, 0x04, 0x01, 0xEF,
+ 0x06, 0xFF, 0x01, 0xFB, 0x01, 0x10, 0x0B, 0x00, 0x01, 0x19, 0x05, 0xFF,
+ 0x01, 0xFC, 0x01, 0x50, 0x0D, 0x00, 0x01, 0x15, 0x01, 0x9B, 0x01, 0xDE,
+ 0x01, 0xDC, 0x01, 0xA7, 0x01, 0x20, 0xBE, 0x00,
+
+ /* 30 */
+ 0xAB, 0x00, 0x01, 0x13, 0x01, 0x56, 0x01, 0x54, 0x01, 0x20, 0x06, 0x00,
+ 0x01, 0x1E, 0x01, 0xEE, 0x01, 0xB0, 0x05, 0x00, 0x01, 0x02, 0x01, 0x8D,
+ 0x03, 0xFF, 0x01, 0xFE, 0x01, 0x93, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x04, 0x00, 0x01, 0x01, 0x01, 0x9F, 0x06, 0xFF, 0x01, 0xB2,
+ 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x04, 0x00, 0x01, 0x3E,
+ 0x08, 0xFF, 0x01, 0x50, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x03, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x01, 0xFC, 0x01, 0x62, 0x01, 0x00,
+ 0x01, 0x02, 0x01, 0x6B, 0x02, 0xFF, 0x01, 0xF6, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x40, 0x04, 0x00, 0x01, 0x3D, 0x02, 0xFF, 0x01, 0x30, 0x02, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0xD1, 0x05, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xD0,
+ 0x02, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0x04,
+ 0x02, 0xFF, 0x01, 0x10, 0x06, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0xF7,
+ 0x02, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF6, 0x07, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFD,
+ 0x02, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x40,
+ 0x01, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0x80, 0x08, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x90,
+ 0x01, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x20, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x01, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF0, 0x01, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x01, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xFC, 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x00,
+ 0x01, 0x1F, 0x05, 0xFF, 0x01, 0xFB, 0x09, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xF4, 0x01, 0x00, 0x01, 0x1F, 0x05, 0xFF, 0x01, 0xFA, 0x09, 0x00,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF5, 0x01, 0x00, 0x01, 0x1F, 0x05, 0xFF,
+ 0x01, 0xF9, 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF5, 0x01, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE5, 0x01, 0x55, 0x01, 0x57, 0x01, 0xFF,
+ 0x01, 0xFA, 0x09, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x01, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xFB, 0x09, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x02, 0x00, 0x01, 0xFF, 0x01, 0xFD,
+ 0x09, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF1, 0x01, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x10,
+ 0x08, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x02, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x50,
+ 0x08, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x50, 0x01, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x02, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2,
+ 0x07, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xFE, 0x02, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x02, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFB,
+ 0x07, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x02, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x02, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x70,
+ 0x06, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xD0, 0x02, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF7,
+ 0x05, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0x30, 0x02, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x09, 0x02, 0xFF, 0x01, 0xC4,
+ 0x03, 0x00, 0x01, 0x03, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xF6, 0x03, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x04, 0x00, 0x01, 0x9F, 0x02, 0xFF,
+ 0x01, 0xEA, 0x01, 0x87, 0x01, 0x8A, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0x50,
+ 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x04, 0x00, 0x01, 0x06,
+ 0x07, 0xFF, 0x01, 0xD4, 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x05, 0x00, 0x01, 0x19, 0x05, 0xFF, 0x01, 0xE7, 0x0E, 0x00, 0x01, 0x04,
+ 0x01, 0x9B, 0x01, 0xCE, 0x01, 0xDC, 0x01, 0x95, 0xB9, 0x00,
+
+ /* 31 */
+ 0xB7, 0x00, 0x01, 0x04, 0x01, 0x9C, 0x01, 0xDE, 0x06, 0xEE, 0x01, 0xC0,
+ 0x09, 0x00, 0x01, 0x04, 0x01, 0xDF, 0x08, 0xFF, 0x01, 0xD0, 0x09, 0x00,
+ 0x01, 0x6F, 0x09, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x04, 0x02, 0xFF,
+ 0x01, 0xFB, 0x01, 0x87, 0x04, 0x77, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x08, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x20, 0x05, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0xE1, 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x60, 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xD0, 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x06, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x10, 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x20, 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xD0, 0x08, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xFA, 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xD0, 0x08, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xE8,
+ 0x01, 0x54, 0x04, 0x44, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xD0, 0x09, 0x00,
+ 0x01, 0x4F, 0x09, 0xFF, 0x01, 0xD0, 0x09, 0x00, 0x01, 0x03, 0x01, 0xDF,
+ 0x08, 0xFF, 0x01, 0xD0, 0x0A, 0x00, 0x01, 0x05, 0x01, 0xAE, 0x07, 0xFF,
+ 0x01, 0xD0, 0x0C, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x32,
+ 0x01, 0x22, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xD0, 0x0C, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0xE2, 0x02, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x0B, 0x00, 0x01, 0x08, 0x02, 0xFF, 0x01, 0x30, 0x02, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x0B, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF5,
+ 0x03, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x0A, 0x00, 0x01, 0x04,
+ 0x02, 0xFF, 0x01, 0x60, 0x03, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x09, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0x90, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x09, 0x00,
+ 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xD0, 0x09, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x10, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xE1, 0x06, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0x20,
+ 0x06, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0, 0x07, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0xF4, 0x07, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xD0,
+ 0xCF, 0x00,
+
+ /* 32 */
+ 0xFF, 0x00, 0x45, 0x00, 0x01, 0x01, 0x01, 0x11, 0x10, 0x00, 0x01, 0x02,
+ 0x01, 0x8D, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0x93, 0x0E, 0x00, 0x01, 0x9F,
+ 0x05, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0x0B, 0x06, 0xFF, 0x01, 0xFB,
+ 0x0C, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x42, 0x01, 0x12,
+ 0x01, 0x4A, 0x02, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x30, 0x03, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x90, 0x0B, 0x00,
+ 0x01, 0xFF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xB0,
+ 0x0A, 0x00, 0x01, 0x02, 0x01, 0xDD, 0x01, 0xD5, 0x04, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xC0,
+ 0x11, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xC0, 0x0E, 0x00, 0x01, 0x02,
+ 0x01, 0x57, 0x01, 0xAD, 0x02, 0xFF, 0x01, 0xC0, 0x0C, 0x00, 0x01, 0x16,
+ 0x01, 0xAD, 0x05, 0xFF, 0x01, 0xC0, 0x0B, 0x00, 0x01, 0x09, 0x04, 0xFF,
+ 0x01, 0xFE, 0x01, 0x9D, 0x01, 0xFF, 0x01, 0xC0, 0x0B, 0x00, 0x01, 0xCF,
+ 0x02, 0xFF, 0x01, 0xC9, 0x01, 0x64, 0x01, 0x10, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x71,
+ 0x03, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xC0,
+ 0x0A, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x70,
+ 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xC0,
+ 0x0A, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2, 0x03, 0x00, 0x01, 0x0A,
+ 0x02, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0x83,
+ 0x01, 0x12, 0x01, 0x48, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xF4, 0x0B, 0x00,
+ 0x01, 0xCF, 0x05, 0xFF, 0x01, 0x76, 0x02, 0xFF, 0x01, 0xF6, 0x0A, 0x00,
+ 0x01, 0x1B, 0x04, 0xFF, 0x01, 0xC3, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x39, 0x01, 0xCE, 0x01, 0xDC, 0x01, 0x94,
+ 0x02, 0x00, 0x01, 0x2A, 0x01, 0xDE, 0x01, 0xB3, 0xBD, 0x00,
+
+ /* 33 */
+ 0x93, 0x00, 0x01, 0x03, 0x01, 0xCC, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xD0, 0x10, 0x00, 0x01, 0x26, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0xA0, 0x0D, 0x00, 0x01, 0x02, 0x01, 0x69, 0x01, 0xBE, 0x03, 0xFF,
+ 0x01, 0x40, 0x0C, 0x00, 0x01, 0x02, 0x01, 0xCF, 0x04, 0xFF, 0x01, 0xF6,
+ 0x0D, 0x00, 0x01, 0x3F, 0x03, 0xFF, 0x01, 0xFE, 0x01, 0xA6, 0x01, 0x10,
+ 0x0D, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x85, 0x01, 0x10,
+ 0x0E, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF6, 0x11, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x40, 0x11, 0x00, 0x01, 0x7F, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x10, 0x0F, 0x00, 0x01, 0xDF, 0x01, 0xE0, 0x01, 0x3A, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x71, 0x0C, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0x99, 0x04, 0xFF, 0x01, 0xFE, 0x01, 0x60, 0x0B, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xDF, 0x05, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0x08,
+ 0x02, 0xFF, 0x01, 0xFE, 0x01, 0x72, 0x01, 0x11, 0x01, 0x5B, 0x02, 0xFF,
+ 0x01, 0x50, 0x0A, 0x00, 0x01, 0x0B, 0x02, 0xFF, 0x01, 0xC1, 0x03, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xE1, 0x0A, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x10, 0x03, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF7,
+ 0x0A, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF6, 0x04, 0x00, 0x01, 0x01,
+ 0x01, 0xFF, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF1,
+ 0x05, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x10, 0x09, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x50,
+ 0x09, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x90, 0x05, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x80,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x70, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x90,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x80, 0x05, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x90,
+ 0x05, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x50,
+ 0x09, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF1, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x10, 0x09, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF8,
+ 0x04, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFD, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF6,
+ 0x0B, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xE3, 0x03, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0xD0, 0x0B, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0xA6,
+ 0x01, 0x45, 0x01, 0x8E, 0x02, 0xFF, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x01,
+ 0x01, 0xCF, 0x05, 0xFF, 0x01, 0xF5, 0x0D, 0x00, 0x01, 0x08, 0x04, 0xFF,
+ 0x01, 0xFC, 0x01, 0x30, 0x0E, 0x00, 0x01, 0x16, 0x01, 0xAC, 0x01, 0xED,
+ 0x01, 0xC8, 0x01, 0x30, 0xC0, 0x00,
+
+ /* 34 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x67, 0x04, 0x77, 0x01, 0x63, 0x0E, 0x00,
+ 0x01, 0xEF, 0x05, 0xFF, 0x01, 0xD5, 0x0D, 0x00, 0x01, 0xEF, 0x06, 0xFF,
+ 0x01, 0x60, 0x0C, 0x00, 0x01, 0xEF, 0x01, 0xFD, 0x02, 0x99, 0x01, 0xAC,
+ 0x02, 0xFF, 0x01, 0xF1, 0x0C, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00,
+ 0x01, 0x2D, 0x01, 0xFF, 0x01, 0xF5, 0x0C, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x03, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF7, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x03, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x0C, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x2D, 0x01, 0xFF, 0x01, 0xE0,
+ 0x0C, 0x00, 0x01, 0xEF, 0x01, 0xFD, 0x02, 0x99, 0x01, 0xAC, 0x02, 0xFF,
+ 0x01, 0x40, 0x0C, 0x00, 0x01, 0xEF, 0x05, 0xFF, 0x01, 0xF3, 0x0D, 0x00,
+ 0x01, 0xEF, 0x05, 0xFF, 0x01, 0xFE, 0x01, 0x60, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xFC, 0x03, 0x88, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xF8, 0x0C, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x02, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0x30, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0x70, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x90, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x04, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x90, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x70, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xFA, 0x03, 0x22, 0x01, 0x4B, 0x02, 0xFF, 0x01, 0x10,
+ 0x0B, 0x00, 0x01, 0xEF, 0x06, 0xFF, 0x01, 0xF8, 0x0C, 0x00, 0x01, 0xEF,
+ 0x06, 0xFF, 0x01, 0x80, 0x0C, 0x00, 0x01, 0xEF, 0x04, 0xFF, 0x01, 0xFD,
+ 0x01, 0x93, 0xD4, 0x00,
+
+ /* 35 */
+ 0xFF, 0x00, 0x56, 0x00, 0x06, 0x77, 0x01, 0x70, 0x0D, 0x00, 0x01, 0xEF,
+ 0x05, 0xFF, 0x01, 0xF0, 0x0D, 0x00, 0x01, 0xEF, 0x05, 0xFF, 0x01, 0xF0,
+ 0x0D, 0x00, 0x01, 0xEF, 0x01, 0xFD, 0x04, 0x99, 0x01, 0x90, 0x0D, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0xD9, 0x00,
+
+ /* 36 */
+ 0xFF, 0x00, 0x58, 0x00, 0x01, 0x57, 0x06, 0x77, 0x01, 0x20, 0x0C, 0x00,
+ 0x01, 0xCF, 0x06, 0xFF, 0x01, 0x50, 0x0C, 0x00, 0x01, 0xDF, 0x06, 0xFF,
+ 0x01, 0x50, 0x0C, 0x00, 0x01, 0xDF, 0x01, 0xFD, 0x03, 0x99, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x50, 0x0C, 0x00, 0x01, 0xDF, 0x01, 0xFA, 0x03, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50, 0x0C, 0x00, 0x01, 0xEF, 0x01, 0xFA,
+ 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xFA, 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50, 0x0C, 0x00,
+ 0x01, 0xEF, 0x01, 0xFA, 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50,
+ 0x0C, 0x00, 0x01, 0xFF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF,
+ 0x01, 0x50, 0x0C, 0x00, 0x01, 0xFF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF8,
+ 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF6, 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50,
+ 0x0B, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF5, 0x03, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF3,
+ 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF0, 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50,
+ 0x0B, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x90,
+ 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0x30, 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x50,
+ 0x0A, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFD, 0x04, 0x22, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0x50, 0x09, 0x00, 0x01, 0x6A, 0x01, 0xAE, 0x08, 0xFF,
+ 0x01, 0xCA, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x9F, 0x0A, 0xFF, 0x01, 0xF0,
+ 0x08, 0x00, 0x01, 0x9F, 0x0A, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x9F,
+ 0x01, 0xF5, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x9F,
+ 0x01, 0xF5, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x9F,
+ 0x01, 0xF5, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x9F,
+ 0x01, 0xF5, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x8E,
+ 0x01, 0xE5, 0x08, 0x00, 0x01, 0xDE, 0x01, 0xE0, 0x6C, 0x00,
+
+ /* 37 */
+ 0xFF, 0x00, 0x58, 0x00, 0x01, 0x28, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFC,
+ 0x01, 0x71, 0x0E, 0x00, 0x01, 0x09, 0x05, 0xFF, 0x01, 0x60, 0x0C, 0x00,
+ 0x01, 0x01, 0x01, 0xCF, 0x05, 0xFF, 0x01, 0xF8, 0x0C, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x73, 0x01, 0x11, 0x01, 0x5B, 0x02, 0xFF,
+ 0x01, 0x50, 0x0B, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xC1, 0x03, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xE0, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xFE,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF6, 0x0A, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF5, 0x05, 0x00, 0x01, 0xDF, 0x01, 0xFC,
+ 0x0A, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xE0, 0x05, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x0A, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xB0, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x30, 0x09, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xC6, 0x05, 0x66, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x60, 0x09, 0x00,
+ 0x01, 0x1F, 0x09, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x2F, 0x09, 0xFF,
+ 0x01, 0x80, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xB6, 0x07, 0x66,
+ 0x01, 0x30, 0x09, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x80, 0x11, 0x00,
+ 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xB0, 0x11, 0x00, 0x01, 0x0A, 0x01, 0xFF,
+ 0x01, 0xF0, 0x05, 0x00, 0x01, 0x48, 0x01, 0x88, 0x0A, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xEF, 0x01, 0xFC, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xFE, 0x01, 0x10, 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xD2, 0x03, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xE1, 0x0B, 0x00, 0x01, 0x0C, 0x02, 0xFF,
+ 0x01, 0xA6, 0x01, 0x45, 0x01, 0x7C, 0x02, 0xFF, 0x01, 0x50, 0x0B, 0x00,
+ 0x01, 0x01, 0x01, 0xCF, 0x05, 0xFF, 0x01, 0xF6, 0x0D, 0x00, 0x01, 0x08,
+ 0x04, 0xFF, 0x01, 0xFD, 0x01, 0x40, 0x0E, 0x00, 0x01, 0x16, 0x01, 0xAD,
+ 0x01, 0xEE, 0x01, 0xC9, 0x01, 0x40, 0xC0, 0x00,
+
+ /* 38 */
+ 0xFF, 0x00, 0x55, 0x00, 0x01, 0x03, 0x02, 0x77, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0x77, 0x01, 0x71, 0x03, 0x00, 0x01, 0x06, 0x01, 0x77, 0x01, 0x73,
+ 0x06, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xB0, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x06, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFB, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF4, 0x02, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xFB,
+ 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF4, 0x02, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFA, 0x01, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFC,
+ 0x0A, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xA0, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF4, 0x01, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF4,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x93, 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xC1,
+ 0x0C, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFB, 0x01, 0xFF, 0x01, 0xFB,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x10, 0x0D, 0x00, 0x01, 0xCF, 0x04, 0xFF,
+ 0x01, 0xD1, 0x0E, 0x00, 0x01, 0x0D, 0x03, 0xFF, 0x01, 0xFD, 0x01, 0x10,
+ 0x0E, 0x00, 0x01, 0x5F, 0x04, 0xFF, 0x01, 0x60, 0x0D, 0x00, 0x01, 0x05,
+ 0x05, 0xFF, 0x01, 0xF6, 0x0D, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xE5,
+ 0x01, 0xFF, 0x01, 0xF5, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x60, 0x0B, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x23, 0x01, 0xFF, 0x01, 0xF4,
+ 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xF7, 0x0B, 0x00, 0x01, 0x6F, 0x01, 0xFF,
+ 0x01, 0xE2, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x01, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x20, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x00, 0x01, 0x1D,
+ 0x01, 0xFF, 0x01, 0xF7, 0x09, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xD1,
+ 0x01, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x00, 0x01, 0x01,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x70, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x10, 0x01, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF4,
+ 0x02, 0x00, 0x01, 0x1C, 0x01, 0xFF, 0x01, 0xF8, 0x07, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0xD1, 0x02, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF4,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x80, 0x05, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x10, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00, 0x01, 0x1C, 0x01, 0xFF, 0x01, 0xF8,
+ 0x05, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xD1, 0x03, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x80, 0xCC, 0x00,
+
+ /* 39 */
+ 0xFF, 0x00, 0x45, 0x00, 0x01, 0x01, 0x11, 0x00, 0x01, 0x17, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0xA5, 0x0E, 0x00, 0x01, 0x06, 0x05, 0xFF,
+ 0x01, 0xD3, 0x0D, 0x00, 0x01, 0x5F, 0x06, 0xFF, 0x01, 0x30, 0x0C, 0x00,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xC5, 0x01, 0x21, 0x01, 0x26, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0xD0, 0x0B, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFB,
+ 0x03, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF5, 0x0B, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xF3, 0x03, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9,
+ 0x0B, 0x00, 0x01, 0x05, 0x01, 0x88, 0x01, 0x80, 0x04, 0x00, 0x01, 0xFF,
+ 0x01, 0xFA, 0x11, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF9, 0x11, 0x00,
+ 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF4, 0x0E, 0x00, 0x01, 0x01, 0x01, 0x33,
+ 0x01, 0x36, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xB0, 0x0E, 0x00, 0x01, 0x09,
+ 0x03, 0xFF, 0x01, 0xFA, 0x01, 0x10, 0x0E, 0x00, 0x01, 0x09, 0x03, 0xFF,
+ 0x01, 0xFA, 0x01, 0x10, 0x0E, 0x00, 0x01, 0x08, 0x01, 0xEE, 0x03, 0xFF,
+ 0x01, 0xE3, 0x10, 0x00, 0x01, 0x01, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xFD,
+ 0x11, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0x40, 0x0A, 0x00, 0x01, 0x06,
+ 0x01, 0x66, 0x01, 0x30, 0x04, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x70,
+ 0x0A, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xB0, 0x04, 0x00, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0x80, 0x0A, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF1,
+ 0x04, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x60, 0x0A, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xFB, 0x03, 0x00, 0x01, 0x04, 0x02, 0xFF, 0x01, 0x10,
+ 0x0A, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0xE8, 0x01, 0x53, 0x01, 0x46,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xF8, 0x0C, 0x00, 0x01, 0x7F, 0x06, 0xFF,
+ 0x01, 0xB0, 0x0C, 0x00, 0x01, 0x06, 0x01, 0xEF, 0x04, 0xFF, 0x01, 0xF7,
+ 0x0E, 0x00, 0x01, 0x05, 0x01, 0x9C, 0x01, 0xDE, 0x01, 0xDC, 0x01, 0x95,
+ 0xC1, 0x00,
+
+ /* 40 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x74, 0x04, 0x00, 0x01, 0x05,
+ 0x01, 0x77, 0x01, 0x76, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x03, 0x00, 0x01, 0x05, 0x02, 0xFF, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x0E, 0x02, 0xFF, 0x01, 0xFE,
+ 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFF,
+ 0x01, 0xCF, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xE1,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x70, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0xCF, 0x01, 0xFD, 0x01, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x00, 0x01, 0x9F, 0x01, 0xFE,
+ 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x01, 0xB0, 0x01, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x20, 0x01, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xE0, 0x02, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x01, 0xDF, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x9F,
+ 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xF3, 0x03, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xA0,
+ 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x02, 0xFF,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xE0, 0x04, 0x00, 0x01, 0x9F, 0x01, 0xFE,
+ 0xD2, 0x00,
+
+ /* 41 */
+ 0xCA, 0x00, 0x01, 0x2A, 0x01, 0xA2, 0x03, 0x00, 0x01, 0x3A, 0x01, 0xA2,
+ 0x0D, 0x00, 0x01, 0x2F, 0x01, 0xF9, 0x03, 0x00, 0x01, 0xAF, 0x01, 0xF1,
+ 0x0D, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x82, 0x01, 0x00, 0x01, 0x29,
+ 0x01, 0xFF, 0x01, 0xC0, 0x0D, 0x00, 0x01, 0x05, 0x05, 0xFF, 0x01, 0x30,
+ 0x0E, 0x00, 0x01, 0x7F, 0x03, 0xFF, 0x01, 0xF6, 0x0F, 0x00, 0x01, 0x02,
+ 0x01, 0x8B, 0x01, 0xDD, 0x01, 0xB8, 0x01, 0x10, 0x21, 0x00, 0x01, 0x67,
+ 0x01, 0x74, 0x04, 0x00, 0x01, 0x05, 0x01, 0x77, 0x01, 0x76, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xFE,
+ 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x05,
+ 0x02, 0xFF, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00,
+ 0x01, 0x0E, 0x02, 0xFF, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xCF, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF1, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x70,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0xCF, 0x01, 0xFD, 0x01, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF4,
+ 0x01, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xB0, 0x01, 0x00, 0x01, 0x9F,
+ 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x20, 0x01, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xE0, 0x02, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0xDF,
+ 0x01, 0xFC, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF,
+ 0x02, 0xFF, 0x01, 0xF3, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00,
+ 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xA0, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFE,
+ 0x0B, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0x10, 0x03, 0x00, 0x01, 0x9F,
+ 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xE0,
+ 0x04, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0xD2, 0x00,
+
+ /* 42 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x74, 0x04, 0x00, 0x01, 0x67,
+ 0x01, 0x77, 0x01, 0x10, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x03, 0x00,
+ 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF6, 0x0C, 0x00, 0x01, 0xEF, 0x01, 0xF8,
+ 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x60, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xF8, 0x02, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF5, 0x0D, 0x00,
+ 0x01, 0xEF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x50,
+ 0x0D, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x0A, 0x01, 0xFF,
+ 0x01, 0xF5, 0x0E, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x50, 0x0E, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF4, 0x0F, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x40, 0x0F, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xF4,
+ 0x10, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0xEF,
+ 0x02, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xFA,
+ 0x10, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x0F, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xFB,
+ 0x0F, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x0E, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xFB, 0x0E, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x02, 0x00,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xC0, 0x0D, 0x00, 0x01, 0xEF, 0x01, 0xF8,
+ 0x02, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFC, 0x0D, 0x00, 0x01, 0xEF,
+ 0x01, 0xF8, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xC0, 0x0C, 0x00,
+ 0x01, 0xEF, 0x01, 0xF8, 0x03, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFC,
+ 0x0C, 0x00, 0x01, 0xEF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x9F, 0x01, 0xFF,
+ 0x01, 0xC1, 0xD2, 0x00,
+
+ /* 43 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x02, 0x06, 0x77, 0x01, 0x75, 0x0C, 0x00,
+ 0x01, 0x05, 0x06, 0xFF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x05, 0x06, 0xFF,
+ 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFB, 0x03, 0xAA,
+ 0x01, 0xEF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2,
+ 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xF2, 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF2, 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC, 0x0C, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2, 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC,
+ 0x0C, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x03, 0x00, 0x01, 0xBF,
+ 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x03, 0x00,
+ 0x01, 0xBF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0,
+ 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xF0, 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF0, 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC, 0x0C, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC,
+ 0x0C, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00, 0x01, 0xBF,
+ 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x80, 0x03, 0x00,
+ 0x01, 0xBF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x40,
+ 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x9F, 0x01, 0xFF,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0xBF, 0x01, 0xFC, 0x0B, 0x00, 0x01, 0x04,
+ 0x01, 0xFF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0xBF, 0x01, 0xFC, 0x0B, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xBF, 0x01, 0xFC,
+ 0x0B, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x70, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0xFC, 0x0B, 0x00, 0x01, 0x9F, 0x01, 0xF6, 0x05, 0x00, 0x01, 0xBF,
+ 0x01, 0xFC, 0x0B, 0x00, 0x01, 0x34, 0xC7, 0x00,
+
+ /* 44 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x77, 0x01, 0x30, 0x04, 0x00,
+ 0x01, 0x03, 0x02, 0x77, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xD0,
+ 0x04, 0x00, 0x01, 0x0B, 0x02, 0xFF, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xF3, 0x04, 0x00, 0x01, 0x2F, 0x02, 0xFF, 0x0A, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0xFA, 0x04, 0x00, 0x01, 0x9F, 0x02, 0xFF, 0x0A, 0x00,
+ 0x01, 0xEF, 0x02, 0xFF, 0x01, 0x10, 0x03, 0x00, 0x03, 0xFF, 0x0A, 0x00,
+ 0x01, 0xEF, 0x02, 0xFF, 0x01, 0x80, 0x02, 0x00, 0x01, 0x06, 0x03, 0xFF,
+ 0x0A, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xE0, 0x02, 0x00, 0x01, 0x0D,
+ 0x03, 0xFF, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFD, 0x01, 0xFF, 0x01, 0xF5,
+ 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xDF, 0x01, 0xFF, 0x0A, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x01, 0xDF, 0x01, 0xFC, 0x02, 0x00, 0x01, 0xAF,
+ 0x01, 0xFE, 0x01, 0x8F, 0x01, 0xFF, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x30, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF8,
+ 0x01, 0x7F, 0x01, 0xFF, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x90, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF2, 0x01, 0x7F,
+ 0x01, 0xFF, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x0A, 0x01, 0xFF,
+ 0x01, 0xF1, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xB0, 0x01, 0x7F, 0x01, 0xFF,
+ 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x40, 0x01, 0x7F, 0x01, 0xFF, 0x0A, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x00, 0x01, 0xCF, 0x01, 0xFD, 0x01, 0xCF,
+ 0x01, 0xFE, 0x01, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x0A, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0x00, 0x01, 0x6F, 0x02, 0xFF, 0x01, 0xF7, 0x01, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x00,
+ 0x01, 0x0F, 0x02, 0xFF, 0x01, 0xF1, 0x01, 0x00, 0x01, 0x7F, 0x01, 0xFF,
+ 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x00, 0x01, 0x09, 0x02, 0xFF,
+ 0x01, 0xA0, 0x01, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x0A, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0x40, 0x01, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0xCF, 0x01, 0xFD, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x0A, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x5F, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0x61, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x0A, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x06, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0xD1, 0x00,
+
+ /* 45 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x74, 0x05, 0x00, 0x01, 0x77,
+ 0x01, 0x73, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xFD, 0x05, 0xAA, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x07, 0xFF, 0x01, 0xF8, 0x0B, 0x00,
+ 0x01, 0xEF, 0x07, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xFC,
+ 0x05, 0x77, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0xD2, 0x00,
+
+ /* 46 */
+ 0xFF, 0x00, 0x58, 0x00, 0x01, 0x39, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xEB,
+ 0x01, 0x60, 0x0E, 0x00, 0x01, 0x1B, 0x04, 0xFF, 0x01, 0xFE, 0x01, 0x50,
+ 0x0C, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x05, 0xFF, 0x01, 0xF8, 0x0C, 0x00,
+ 0x01, 0x0D, 0x02, 0xFF, 0x01, 0x83, 0x01, 0x12, 0x01, 0x5C, 0x02, 0xFF,
+ 0x01, 0x50, 0x0B, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xD1, 0x03, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xE1, 0x0A, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x10, 0x03, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF7,
+ 0x0A, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0x01,
+ 0x01, 0xFF, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF1,
+ 0x05, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x10, 0x09, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x50,
+ 0x09, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x90, 0x05, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x80,
+ 0x05, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x70, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x90,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x80, 0x05, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x90,
+ 0x05, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x50,
+ 0x09, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF1, 0x05, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x10, 0x09, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF8,
+ 0x04, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xFD, 0x0B, 0x00, 0x02, 0xFF,
+ 0x01, 0x20, 0x03, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF6, 0x0B, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xE3, 0x03, 0x00, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0xD0, 0x0B, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0xA5, 0x01, 0x34,
+ 0x01, 0x7E, 0x02, 0xFF, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x01, 0x01, 0xCF,
+ 0x05, 0xFF, 0x01, 0xF5, 0x0D, 0x00, 0x01, 0x19, 0x04, 0xFF, 0x01, 0xFC,
+ 0x01, 0x30, 0x0E, 0x00, 0x01, 0x27, 0x01, 0xBD, 0x01, 0xEE, 0x01, 0xC9,
+ 0x01, 0x40, 0xC0, 0x00,
+
+ /* 47 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x67, 0x07, 0x77, 0x01, 0x73, 0x0B, 0x00,
+ 0x01, 0xEF, 0x07, 0xFF, 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x07, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xFD, 0x05, 0xAA, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0xD2, 0x00,
+
+ /* 48 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x72, 0x01, 0x00, 0x01, 0x29,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xC7, 0x01, 0x10, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xF4, 0x01, 0x08, 0x04, 0xFF, 0x01, 0xF6, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xF4, 0x01, 0xAF, 0x05, 0xFF, 0x01, 0x80, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xFC, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0x42, 0x01, 0x37, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0xF6, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x30, 0x02, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10,
+ 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF3, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x70, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x0A, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF2,
+ 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xF5, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF7, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFA, 0x06, 0x00,
+ 0x01, 0xFF, 0x01, 0xF8, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x06, 0x00,
+ 0x01, 0xFF, 0x01, 0xF9, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFA, 0x06, 0x00,
+ 0x01, 0xFF, 0x01, 0xF9, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFB, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFE,
+ 0x05, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF5, 0x0A, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF2,
+ 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF4,
+ 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x70, 0x0A, 0x00, 0x01, 0xEF,
+ 0x02, 0xFF, 0x01, 0x40, 0x02, 0x00, 0x01, 0x1B, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x10, 0x0A, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x64,
+ 0x01, 0x58, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF5, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0xAF, 0x05, 0xFF, 0x01, 0x70, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0x08, 0x04, 0xFF, 0x01, 0xE4, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0x00, 0x01, 0x28, 0x01, 0xCE, 0x01, 0xED, 0x01, 0xA5,
+ 0x0D, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xDE, 0x01, 0xE8,
+ 0x25, 0x00,
+
+ /* 49 */
+ 0xFF, 0x00, 0x58, 0x00, 0x01, 0x38, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xEA,
+ 0x01, 0x50, 0x0E, 0x00, 0x01, 0x19, 0x04, 0xFF, 0x01, 0xFD, 0x01, 0x20,
+ 0x0C, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x05, 0xFF, 0x01, 0xF2, 0x0C, 0x00,
+ 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x73, 0x01, 0x12, 0x01, 0x6D,
+ 0x01, 0xFF, 0x01, 0xFD, 0x0C, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xC1,
+ 0x03, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x60, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xFE, 0x01, 0x10, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x0A, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF6, 0x04, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF0, 0x0A, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF1,
+ 0x04, 0x00, 0x01, 0x04, 0x01, 0xBB, 0x01, 0xB1, 0x0A, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x90,
+ 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x80, 0x11, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x70, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x80,
+ 0x11, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x90, 0x11, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x55, 0x01, 0x52, 0x0A, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF1, 0x04, 0x00, 0x01, 0x04, 0x01, 0xFF,
+ 0x01, 0xF4, 0x0A, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF6, 0x04, 0x00,
+ 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF1, 0x0B, 0x00, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xC0, 0x0B, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xD2, 0x02, 0x00, 0x01, 0x01, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x60, 0x0B, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0x94,
+ 0x01, 0x34, 0x01, 0x8E, 0x01, 0xFF, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x01,
+ 0x01, 0xDF, 0x05, 0xFF, 0x01, 0xE1, 0x0D, 0x00, 0x01, 0x19, 0x04, 0xFF,
+ 0x01, 0xFA, 0x01, 0x10, 0x0E, 0x00, 0x01, 0x27, 0x01, 0xCD, 0x01, 0xEE,
+ 0x01, 0xC8, 0x01, 0x20, 0xC0, 0x00,
+
+ /* 50 */
+ 0xFF, 0x00, 0x55, 0x00, 0x01, 0x47, 0x06, 0x77, 0x01, 0x76, 0x0C, 0x00,
+ 0x01, 0x9F, 0x06, 0xFF, 0x01, 0xFE, 0x0C, 0x00, 0x01, 0x9F, 0x06, 0xFF,
+ 0x01, 0xFE, 0x0C, 0x00, 0x01, 0x6A, 0x02, 0xAA, 0x01, 0xDF, 0x01, 0xFF,
+ 0x02, 0xAA, 0x01, 0xA9, 0x0F, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00, 0x01, 0x9F, 0x01, 0xFE, 0x12, 0x00,
+ 0x01, 0x9F, 0x01, 0xFE, 0xD7, 0x00,
+
+ /* 51 */
+ 0xFF, 0x00, 0x55, 0x00, 0x01, 0x67, 0x01, 0x75, 0x05, 0x00, 0x01, 0x05,
+ 0x01, 0x77, 0x01, 0x70, 0x0A, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x05, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xB0, 0x0A, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0x50, 0x04, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x50, 0x0A, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xB0, 0x04, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x0B, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF0, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0xFF, 0x01, 0xF9, 0x0B, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF5,
+ 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xFB, 0x03, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xD0, 0x0C, 0x00,
+ 0x01, 0x9F, 0x01, 0xFF, 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x70,
+ 0x0C, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x50, 0x02, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x20, 0x0C, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xB0,
+ 0x02, 0x00, 0x01, 0xEF, 0x01, 0xFB, 0x0D, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xF1, 0x01, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF5, 0x0D, 0x00,
+ 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF5, 0x01, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xF0, 0x0E, 0x00, 0x01, 0xEF, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0x90, 0x0E, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x10,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x40, 0x0E, 0x00, 0x01, 0x3F, 0x01, 0xFF,
+ 0x01, 0x50, 0x01, 0xBF, 0x01, 0xFD, 0x0F, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xB1, 0x01, 0xFF, 0x01, 0xF8, 0x0F, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xF7, 0x01, 0xFF, 0x01, 0xF2, 0x0F, 0x00, 0x01, 0x03, 0x03, 0xFF,
+ 0x01, 0xC0, 0x10, 0x00, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0x60, 0x10, 0x00,
+ 0x01, 0x8F, 0x02, 0xFF, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFA,
+ 0x11, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF4, 0x11, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x80,
+ 0x11, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x20, 0x11, 0x00, 0x01, 0xEF,
+ 0x01, 0xFC, 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF6, 0x0F, 0x00,
+ 0x01, 0x05, 0x01, 0x76, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xD0, 0x0F, 0x00,
+ 0x01, 0x09, 0x03, 0xFF, 0x01, 0x50, 0x0F, 0x00, 0x01, 0x09, 0x02, 0xFF,
+ 0x01, 0xF7, 0x10, 0x00, 0x01, 0x05, 0x01, 0xCE, 0x01, 0xDA, 0x01, 0x30,
+ 0x24, 0x00,
+
+ /* 52 */
+ 0xE3, 0x00, 0x01, 0x05, 0x01, 0x99, 0x01, 0x80, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0,
+ 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0,
+ 0x0C, 0x00, 0x01, 0x01, 0x01, 0x8D, 0x01, 0xFF, 0x01, 0xEB, 0x01, 0x40,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x02, 0x01, 0x9E, 0x01, 0xFF,
+ 0x01, 0xEA, 0x01, 0x50, 0x07, 0x00, 0x01, 0x6F, 0x03, 0xFF, 0x01, 0xFA,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x5F, 0x03, 0xFF, 0x01, 0xFC,
+ 0x01, 0x20, 0x05, 0x00, 0x01, 0x06, 0x05, 0xFF, 0x01, 0x98, 0x01, 0xFF,
+ 0x01, 0xE4, 0x05, 0xFF, 0x01, 0xD1, 0x05, 0x00, 0x01, 0x3F, 0x01, 0xFF,
+ 0x01, 0xFC, 0x01, 0x53, 0x01, 0x36, 0x01, 0xCF, 0x01, 0xFC, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0xFF, 0x01, 0x83, 0x01, 0x24, 0x01, 0x9F, 0x01, 0xFF,
+ 0x01, 0xFB, 0x05, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x90, 0x02, 0x00,
+ 0x01, 0x0A, 0x03, 0xFF, 0x01, 0xE2, 0x02, 0x00, 0x01, 0x03, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x40, 0x03, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFC,
+ 0x04, 0x00, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0x40, 0x03, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF4,
+ 0x04, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xFB, 0x04, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF1, 0x03, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xE0,
+ 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF6, 0x04, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xB0,
+ 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x03, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF0, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF9, 0x03, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x80, 0x04, 0x00,
+ 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF0, 0x05, 0x00, 0x01, 0xFF, 0x01, 0xFA,
+ 0x03, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x70, 0x04, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xE0, 0x05, 0x00, 0x01, 0xEF, 0x01, 0xFB, 0x03, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x80, 0x04, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xF0, 0x05, 0x00, 0x01, 0xFF, 0x01, 0xFA, 0x03, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF0,
+ 0x05, 0x00, 0x01, 0xFF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xB0, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF3, 0x04, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x03, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF0, 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xF5, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xFC, 0x04, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF1, 0x03, 0x00, 0x01, 0x04, 0x01, 0xFF,
+ 0x01, 0xFC, 0x04, 0x00, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0x40, 0x03, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xB0, 0x04, 0x00, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0xA0, 0x02, 0x00, 0x01, 0x0B, 0x03, 0xFF, 0x01, 0xE3, 0x02, 0x00,
+ 0x01, 0x04, 0x02, 0xFF, 0x01, 0x40, 0x04, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x74, 0x01, 0x47, 0x01, 0xDF, 0x01, 0xFE, 0x03, 0xFF,
+ 0x01, 0x95, 0x01, 0x45, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00,
+ 0x01, 0x08, 0x05, 0xFF, 0x01, 0xB8, 0x01, 0xFF, 0x01, 0xE6, 0x05, 0xFF,
+ 0x01, 0xD1, 0x06, 0x00, 0x01, 0x7F, 0x03, 0xFF, 0x01, 0xFA, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x6F, 0x03, 0xFF, 0x01, 0xFA, 0x01, 0x10,
+ 0x06, 0x00, 0x01, 0x02, 0x01, 0x8C, 0x01, 0xEF, 0x01, 0xDB, 0x01, 0x50,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x02, 0x01, 0x8D, 0x01, 0xEE,
+ 0x01, 0xD9, 0x01, 0x30, 0x0C, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0,
+ 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0,
+ 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0,
+ 0x11, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xE0, 0x1E, 0x00,
+
+ /* 53 */
+ 0xFF, 0x00, 0x55, 0x00, 0x01, 0x37, 0x01, 0x77, 0x01, 0x30, 0x04, 0x00,
+ 0x01, 0x17, 0x01, 0x77, 0x01, 0x40, 0x0A, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xE1, 0x04, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x20, 0x0A, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFB, 0x03, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF6, 0x0C, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x50, 0x02, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xE1, 0x02, 0x00, 0x01, 0xCF, 0x01, 0xFE, 0x01, 0x10, 0x0C, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF5, 0x0E, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x60, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x90, 0x0E, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF2,
+ 0x01, 0xCF, 0x01, 0xFD, 0x0F, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0xFF, 0x01, 0xF3, 0x10, 0x00, 0x01, 0x6F, 0x02, 0xFF, 0x01, 0x70,
+ 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFC, 0x11, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xFD, 0x11, 0x00, 0x01, 0x4F, 0x02, 0xFF, 0x01, 0x80,
+ 0x0F, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xF3, 0x0F, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xE3, 0x01, 0xEF, 0x01, 0xFD, 0x0F, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x50, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x90,
+ 0x0D, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF4, 0x0D, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xE1,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFD, 0x0D, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x50, 0x02, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x90,
+ 0x0B, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFA, 0x03, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xF4, 0x0B, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xE1,
+ 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFE, 0x01, 0x10, 0x0A, 0x00,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x50, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xFF,
+ 0x01, 0xA0, 0x0A, 0x00, 0x02, 0x11, 0x05, 0x00, 0x01, 0x01, 0x01, 0x11,
+ 0x01, 0x10, 0xBE, 0x00,
+
+ /* 54 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x74, 0x05, 0x00, 0x01, 0x77,
+ 0x01, 0x73, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x00, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x05, 0x11, 0x01, 0xFF,
+ 0x01, 0xF7, 0x0B, 0x00, 0x01, 0xEF, 0x07, 0xFF, 0x01, 0xFC, 0x01, 0x99,
+ 0x0A, 0x00, 0x01, 0xEF, 0x09, 0xFF, 0x0A, 0x00, 0x01, 0xEF, 0x09, 0xFF,
+ 0x12, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x12, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x12, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x12, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x12, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x6D, 0x00,
+
+ /* 55 */
+ 0xFF, 0x00, 0x55, 0x00, 0x01, 0x02, 0x01, 0x77, 0x01, 0x71, 0x04, 0x00,
+ 0x01, 0x77, 0x01, 0x73, 0x0B, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2,
+ 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF8,
+ 0x0B, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x0B, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00,
+ 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2,
+ 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF6, 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x0C, 0x00,
+ 0x02, 0xFF, 0x01, 0x85, 0x03, 0x55, 0x01, 0xFF, 0x01, 0xF8, 0x0C, 0x00,
+ 0x01, 0x6F, 0x06, 0xFF, 0x01, 0xF8, 0x0C, 0x00, 0x01, 0x07, 0x06, 0xFF,
+ 0x01, 0xF8, 0x0D, 0x00, 0x01, 0x17, 0x01, 0xBC, 0x03, 0xCC, 0x01, 0xFF,
+ 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x12, 0x00, 0x01, 0x11, 0x01, 0x10, 0xBF, 0x00,
+
+ /* 56 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x66, 0x01, 0x64, 0x02, 0x00, 0x01, 0x01,
+ 0x01, 0x66, 0x01, 0x62, 0x02, 0x00, 0x01, 0x02, 0x01, 0x66, 0x01, 0x60,
+ 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x11, 0x01, 0x13,
+ 0x01, 0xFF, 0x01, 0xF6, 0x02, 0x11, 0x01, 0x17, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0xEF, 0x0A, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF,
+ 0x0A, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x0A, 0xFF, 0x01, 0xF1,
+ 0xCF, 0x00,
+
+ /* 57 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x66, 0x01, 0x63, 0x02, 0x00, 0x01, 0x01,
+ 0x01, 0x66, 0x01, 0x62, 0x02, 0x00, 0x01, 0x02, 0x01, 0x66, 0x01, 0x60,
+ 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF5, 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF1, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x11, 0x01, 0x13,
+ 0x01, 0xFF, 0x01, 0xF6, 0x02, 0x11, 0x01, 0x17, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0xEF, 0x0A, 0xFF, 0x01, 0xF9, 0x01, 0x95, 0x07, 0x00,
+ 0x01, 0xEF, 0x0B, 0xFF, 0x01, 0xF9, 0x07, 0x00, 0x01, 0xEF, 0x0B, 0xFF,
+ 0x01, 0xF9, 0x12, 0x00, 0x01, 0x5F, 0x01, 0xF9, 0x12, 0x00, 0x01, 0x5F,
+ 0x01, 0xF9, 0x12, 0x00, 0x01, 0x5F, 0x01, 0xF9, 0x12, 0x00, 0x01, 0x5F,
+ 0x01, 0xF9, 0x12, 0x00, 0x01, 0x5F, 0x01, 0xF9, 0x6A, 0x00,
+
+ /* 58 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x56, 0x01, 0x63, 0x12, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x02, 0xEE, 0x01, 0xED,
+ 0x01, 0xC9, 0x01, 0x60, 0x0D, 0x00, 0x01, 0xEF, 0x06, 0xFF, 0x01, 0x70,
+ 0x0C, 0x00, 0x01, 0xEF, 0x06, 0xFF, 0x01, 0xFA, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xFA, 0x02, 0x33, 0x01, 0x34, 0x01, 0x6A, 0x02, 0xFF, 0x01, 0x50,
+ 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xFF,
+ 0x01, 0xD0, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF1, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00,
+ 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF3, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x04, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF4, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xE0,
+ 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x11, 0x01, 0x38, 0x02, 0xFF,
+ 0x01, 0x70, 0x0B, 0x00, 0x01, 0xEF, 0x06, 0xFF, 0x01, 0xFC, 0x0C, 0x00,
+ 0x01, 0xEF, 0x06, 0xFF, 0x01, 0xC1, 0x0C, 0x00, 0x01, 0xEF, 0x05, 0xFF,
+ 0x01, 0xB5, 0x0D, 0x00, 0x05, 0x11, 0xC2, 0x00,
+
+ /* 59 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x56, 0x01, 0x63, 0x07, 0x00, 0x01, 0x02,
+ 0x01, 0x66, 0x01, 0x60, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x07, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0,
+ 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x07, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x07, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x02, 0xEE, 0x01, 0xED, 0x01, 0xC9, 0x01, 0x60, 0x02, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x06, 0xFF, 0x01, 0x70,
+ 0x01, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF,
+ 0x06, 0xFF, 0x01, 0xFA, 0x01, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0,
+ 0x08, 0x00, 0x01, 0xEF, 0x01, 0xFA, 0x02, 0x33, 0x01, 0x34, 0x01, 0x6B,
+ 0x02, 0xFF, 0x01, 0x50, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF1, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF4,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF2, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x11, 0x01, 0x37, 0x02, 0xFF, 0x01, 0x70,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x06, 0xFF,
+ 0x01, 0xFC, 0x01, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00,
+ 0x01, 0xEF, 0x06, 0xFF, 0x01, 0xC1, 0x01, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF0, 0x08, 0x00, 0x01, 0xEF, 0x05, 0xFF, 0x01, 0xB5, 0x02, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x05, 0x11, 0x05, 0x00,
+ 0x01, 0x11, 0x01, 0x10, 0xBB, 0x00,
+
+ /* 60 */
+ 0xFF, 0x00, 0x55, 0x00, 0x01, 0x36, 0x04, 0x66, 0x01, 0x63, 0x0E, 0x00,
+ 0x01, 0x9F, 0x04, 0xFF, 0x01, 0xF8, 0x0E, 0x00, 0x01, 0x9F, 0x04, 0xFF,
+ 0x01, 0xF8, 0x0E, 0x00, 0x01, 0x6A, 0x03, 0xAA, 0x01, 0xFF, 0x01, 0xF8,
+ 0x12, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF, 0x01, 0xF8,
+ 0x12, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x12, 0x00, 0x01, 0xFF, 0x01, 0xF8,
+ 0x12, 0x00, 0x02, 0xFF, 0x02, 0xEE, 0x01, 0xED, 0x01, 0xC9, 0x01, 0x50,
+ 0x0D, 0x00, 0x06, 0xFF, 0x01, 0xFE, 0x01, 0x60, 0x0C, 0x00, 0x07, 0xFF,
+ 0x01, 0xF9, 0x0C, 0x00, 0x01, 0xFF, 0x01, 0xFA, 0x02, 0x33, 0x01, 0x34,
+ 0x01, 0x6B, 0x02, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0xFF, 0x01, 0xF8,
+ 0x04, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xC0, 0x0B, 0x00, 0x01, 0xFF,
+ 0x01, 0xF8, 0x04, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF1, 0x0B, 0x00,
+ 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF3,
+ 0x0B, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xF3, 0x0B, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00, 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xE0, 0x0B, 0x00, 0x01, 0xFF, 0x01, 0xF9,
+ 0x03, 0x11, 0x01, 0x38, 0x02, 0xFF, 0x01, 0x70, 0x0B, 0x00, 0x07, 0xFF,
+ 0x01, 0xFC, 0x0C, 0x00, 0x07, 0xFF, 0x01, 0xB1, 0x0C, 0x00, 0x06, 0xFF,
+ 0x01, 0xB5, 0x0D, 0x00, 0x05, 0x11, 0xBF, 0x00,
+
+ /* 61 */
+ 0xFF, 0x00, 0x57, 0x00, 0x01, 0x02, 0x01, 0x8C, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x94, 0x0F, 0x00, 0x01, 0x9F, 0x04, 0xFF, 0x01, 0xB2, 0x0D, 0x00,
+ 0x01, 0x0C, 0x05, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x0C, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x42, 0x01, 0x36, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0xE1, 0x0B, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20,
+ 0x02, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFA, 0x0B, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xF5, 0x04, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x20,
+ 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xE0, 0x04, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x90, 0x0A, 0x00, 0x01, 0x0A, 0x01, 0xCC, 0x01, 0x80,
+ 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xE0, 0x11, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xF1, 0x0D, 0x00, 0x01, 0x69, 0x03, 0x99, 0x01, 0x9B,
+ 0x01, 0xFF, 0x01, 0xF4, 0x0D, 0x00, 0x01, 0xAF, 0x05, 0xFF, 0x01, 0xF5,
+ 0x0D, 0x00, 0x01, 0xAF, 0x05, 0xFF, 0x01, 0xF6, 0x0D, 0x00, 0x01, 0x58,
+ 0x03, 0x88, 0x01, 0x8A, 0x01, 0xFF, 0x01, 0xF5, 0x11, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF4, 0x0A, 0x00, 0x01, 0x05, 0x01, 0x55, 0x01, 0x10,
+ 0x04, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF2, 0x0A, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0x80, 0x04, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xE0,
+ 0x0A, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xD0, 0x04, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xA0, 0x0A, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF5,
+ 0x04, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x40, 0x0A, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x02, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0x42,
+ 0x01, 0x37, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xF2, 0x0C, 0x00, 0x01, 0x0B,
+ 0x06, 0xFF, 0x01, 0x40, 0x0D, 0x00, 0x01, 0x8F, 0x04, 0xFF, 0x01, 0xC2,
+ 0x0E, 0x00, 0x01, 0x01, 0x01, 0x8C, 0x01, 0xEF, 0x01, 0xED, 0x01, 0x94,
+ 0xC1, 0x00,
+
+ /* 62 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x56, 0x01, 0x63, 0x04, 0x00, 0x01, 0x05,
+ 0x01, 0xAE, 0x01, 0xFF, 0x01, 0xED, 0x01, 0x83, 0x09, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x03, 0x00, 0x01, 0x03, 0x01, 0xDF, 0x04, 0xFF, 0x01, 0xA1,
+ 0x08, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x6F, 0x05, 0xFF,
+ 0x01, 0xFE, 0x01, 0x20, 0x07, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x04, 0x02, 0xFF, 0x01, 0xD6, 0x01, 0x32, 0x01, 0x48, 0x02, 0xFF,
+ 0x01, 0xE0, 0x07, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x1C, 0x01, 0xFF, 0x01, 0xF9,
+ 0x07, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFF,
+ 0x01, 0xB0, 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x10,
+ 0x06, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x70, 0x06, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFB,
+ 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xB0, 0x06, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xE0, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xFD,
+ 0x01, 0x99, 0x01, 0x9C, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF1, 0x06, 0x00, 0x01, 0xEF, 0x04, 0xFF, 0x01, 0xF2,
+ 0x05, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF2, 0x06, 0x00, 0x01, 0xEF,
+ 0x04, 0xFF, 0x01, 0xF1, 0x05, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF3,
+ 0x06, 0x00, 0x01, 0xEF, 0x01, 0xFC, 0x01, 0x88, 0x01, 0x8C, 0x01, 0xFF,
+ 0x01, 0xF2, 0x05, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF2, 0x06, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x01, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF3,
+ 0x05, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF1, 0x06, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF0, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x7F, 0x01, 0xFF,
+ 0x01, 0x70, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0x10, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x2D, 0x01, 0xFF, 0x01, 0xF9,
+ 0x07, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x04, 0x02, 0xFF,
+ 0x01, 0xD7, 0x01, 0x32, 0x01, 0x49, 0x02, 0xFF, 0x01, 0xD0, 0x07, 0x00,
+ 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x6F, 0x05, 0xFF, 0x01, 0xFD,
+ 0x01, 0x20, 0x07, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x03,
+ 0x01, 0xDF, 0x04, 0xFF, 0x01, 0xA1, 0x08, 0x00, 0x01, 0x11, 0x01, 0x10,
+ 0x04, 0x00, 0x01, 0x05, 0x01, 0xAD, 0x01, 0xFF, 0x01, 0xEC, 0x01, 0x82,
+ 0xBC, 0x00,
+
+ /* 63 */
+ 0xFF, 0x00, 0x58, 0x00, 0x01, 0x14, 0x05, 0x66, 0x01, 0x60, 0x0C, 0x00,
+ 0x01, 0x2B, 0x06, 0xFF, 0x01, 0xF2, 0x0B, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x06, 0xFF, 0x01, 0xF2, 0x0B, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0xEB,
+ 0x02, 0xAA, 0x01, 0xAC, 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0xF5, 0x03, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2,
+ 0x0B, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x70, 0x03, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x30,
+ 0x03, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2,
+ 0x0B, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x70, 0x03, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF8,
+ 0x01, 0x20, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00,
+ 0x01, 0x08, 0x07, 0xFF, 0x01, 0xF2, 0x0C, 0x00, 0x01, 0x8F, 0x06, 0xFF,
+ 0x01, 0xF2, 0x0C, 0x00, 0x01, 0x02, 0x01, 0x9D, 0x05, 0xFF, 0x01, 0xF2,
+ 0x0D, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x62, 0x01, 0x27,
+ 0x01, 0xFF, 0x01, 0xF2, 0x0D, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF7,
+ 0x01, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2, 0x0D, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x80, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2,
+ 0x0C, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF2, 0x0C, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0,
+ 0x02, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xFA, 0x03, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2,
+ 0x0B, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF2, 0x0A, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFB,
+ 0x04, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2, 0x0A, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x04, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF2,
+ 0x0A, 0x00, 0x02, 0x11, 0x06, 0x00, 0x01, 0x11, 0x01, 0x10, 0xBE, 0x00,
+
+ /* 64 */
+ 0x2C, 0x00, 0x01, 0xBD, 0x01, 0xDD, 0x01, 0x60, 0x01, 0x05, 0x01, 0xDD,
+ 0x01, 0xDC, 0x0E, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x70, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xFE, 0x0E, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x70,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFE, 0x0E, 0x00, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0x70, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFE, 0x0E, 0x00, 0x01, 0x67,
+ 0x01, 0x77, 0x01, 0x30, 0x01, 0x02, 0x01, 0x77, 0x01, 0x76, 0x33, 0x00,
+ 0x01, 0x1C, 0x0A, 0xCC, 0x09, 0x00, 0x01, 0x1F, 0x0A, 0xFF, 0x09, 0x00,
+ 0x01, 0x1F, 0x0A, 0xFF, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE8,
+ 0x08, 0x88, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xFE, 0x07, 0xEE,
+ 0x01, 0xE4, 0x09, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xF5, 0x09, 0x00,
+ 0x01, 0x1F, 0x09, 0xFF, 0x01, 0xF5, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xE7, 0x07, 0x77, 0x01, 0x72, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0xD4, 0x08, 0x44, 0x01, 0x30, 0x08, 0x00, 0x01, 0x1F, 0x0A, 0xFF,
+ 0x01, 0xB0, 0x08, 0x00, 0x01, 0x1F, 0x0A, 0xFF, 0x01, 0xB0, 0x08, 0x00,
+ 0x01, 0x1F, 0x0A, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x01, 0x0A, 0x11,
+ 0xBC, 0x00,
+
+ /* 65 */
+ 0xB6, 0x00, 0x01, 0x01, 0x02, 0x55, 0x01, 0x00, 0x01, 0x04, 0x01, 0x55,
+ 0x01, 0x52, 0x0D, 0x00, 0x01, 0x05, 0x02, 0xFF, 0x01, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0xF7, 0x0D, 0x00, 0x01, 0x05, 0x02, 0xFF, 0x01, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF7, 0x0D, 0x00, 0x01, 0x05, 0x02, 0xFF,
+ 0x01, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF7, 0x0D, 0x00, 0x01, 0x04,
+ 0x02, 0xEE, 0x01, 0x00, 0x01, 0x0C, 0x01, 0xEE, 0x01, 0xE6, 0x4A, 0x00,
+ 0x01, 0x17, 0x01, 0xBE, 0x01, 0xFF, 0x01, 0xDB, 0x01, 0x60, 0x0E, 0x00,
+ 0x01, 0x07, 0x04, 0xFF, 0x01, 0xFE, 0x01, 0x50, 0x0D, 0x00, 0x01, 0xBF,
+ 0x05, 0xFF, 0x01, 0xF7, 0x0C, 0x00, 0x01, 0x0A, 0x02, 0xFF, 0x01, 0x94,
+ 0x01, 0x23, 0x01, 0x6C, 0x02, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xD2, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xFE, 0x01, 0x10, 0x03, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xF6, 0x0A, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF6,
+ 0x05, 0x00, 0x01, 0xEF, 0x01, 0xFB, 0x0A, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xF0, 0x05, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x0A, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0xB0, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x30,
+ 0x09, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xB5, 0x05, 0x55, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0x50, 0x09, 0x00, 0x01, 0x1F, 0x09, 0xFF, 0x01, 0x70,
+ 0x09, 0x00, 0x01, 0x2F, 0x09, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x1F,
+ 0x01, 0xFF, 0x01, 0xB7, 0x07, 0x77, 0x01, 0x40, 0x09, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0x80, 0x11, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xB0,
+ 0x11, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xE0, 0x05, 0x00, 0x01, 0x37,
+ 0x01, 0x77, 0x0A, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF5, 0x05, 0x00,
+ 0x01, 0xDF, 0x01, 0xFD, 0x0B, 0x00, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10,
+ 0x03, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0xC1, 0x03, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF1,
+ 0x0B, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0x94, 0x01, 0x23, 0x01, 0x6B,
+ 0x02, 0xFF, 0x01, 0x60, 0x0B, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x05, 0xFF,
+ 0x01, 0xF8, 0x0D, 0x00, 0x01, 0x19, 0x04, 0xFF, 0x01, 0xFE, 0x01, 0x50,
+ 0x0E, 0x00, 0x01, 0x27, 0x01, 0xCE, 0x01, 0xFF, 0x01, 0xDA, 0x01, 0x50,
+ 0xC0, 0x00,
+
+ /* 48 */
+ 0xFF, 0x00, 0x56, 0x00, 0x01, 0x67, 0x01, 0x72, 0x01, 0x00, 0x01, 0x29,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xC7, 0x01, 0x10, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xF4, 0x01, 0x08, 0x04, 0xFF, 0x01, 0xF6, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xF4, 0x01, 0xAF, 0x05, 0xFF, 0x01, 0x80, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xFC, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0x42, 0x01, 0x37, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0xF6, 0x0B, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x30, 0x02, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10,
+ 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF3, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x70, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x90,
+ 0x04, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x0A, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF2,
+ 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xF5, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF7, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFA, 0x06, 0x00,
+ 0x01, 0xFF, 0x01, 0xF8, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x06, 0x00,
+ 0x01, 0xFF, 0x01, 0xF9, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFA, 0x06, 0x00,
+ 0x01, 0xFF, 0x01, 0xF9, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFB, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF8, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFE,
+ 0x05, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF5, 0x0A, 0x00, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF2,
+ 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xA0, 0x04, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF4,
+ 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x70, 0x0A, 0x00, 0x01, 0xEF,
+ 0x02, 0xFF, 0x01, 0x40, 0x02, 0x00, 0x01, 0x1B, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x10, 0x0A, 0x00, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x64,
+ 0x01, 0x58, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF5, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0xAF, 0x05, 0xFF, 0x01, 0x70, 0x0B, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0x08, 0x04, 0xFF, 0x01, 0xE4, 0x0C, 0x00, 0x01, 0xEF,
+ 0x01, 0xF9, 0x01, 0x00, 0x01, 0x28, 0x01, 0xCE, 0x01, 0xED, 0x01, 0xA5,
+ 0x0D, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9,
+ 0x12, 0x00, 0x01, 0xEF, 0x01, 0xF9, 0x12, 0x00, 0x01, 0xDE, 0x01, 0xE8,
+ 0x25, 0x00,
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp
new file mode 100644
index 0000000..d9acb4f
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp
@@ -0,0 +1,58 @@
+/*******************
+ * font_bitmap.cpp *
+ *******************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if ENABLED(FTDI_EXTENDED)
+
+namespace FTDI {
+
+ uint32_t write_rle_data(uint32_t addr, const uint8_t *data, size_t n) {
+ for (; n >= 2; n -= 2) {
+ uint8_t count = pgm_read_byte(data++);
+ uint8_t value = pgm_read_byte(data++);
+ CLCD::mem_write_fill(addr, value, count);
+ addr += count;
+ }
+ return addr;
+ }
+
+ void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle) {
+ cmd.cmd(BITMAP_HANDLE(handle));
+ cmd.cmd(BITMAP_SOURCE(fm.ptr));
+ cmd.bitmap_layout(fm.format, fm.stride, fm.height);
+ cmd.bitmap_size(BILINEAR, BORDER, BORDER, fm.width, fm.height);
+ }
+
+ void ext_vertex2ii(CommandProcessor &cmd, int x, int y, uint8_t handle, uint8_t cell) {
+ if (x < 0 || y < 0 || x > 511 || y > 511) {
+ cmd.cmd(BITMAP_HANDLE(handle));
+ cmd.cmd(CELL(cell));
+ cmd.cmd(VERTEX2F(x * 16, y * 16));
+ }
+ else {
+ cmd.cmd(VERTEX2II(x, y, handle, cell));
+ }
+ }
+
+} // namespace FTDI
+
+#endif // FTDI_EXTENDED
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.h
new file mode 100644
index 0000000..2b0a533
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.h
@@ -0,0 +1,30 @@
+/******************
+ * font_bitmaps.h *
+ ******************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+class CommandProcessor;
+
+namespace FTDI {
+ uint32_t write_rle_data(uint32_t addr, const uint8_t *data, size_t n);
+ void set_font_bitmap(CommandProcessor& cmd, CLCD::FontMetrics &fm, uint8_t handle);
+ void ext_vertex2ii(CommandProcessor &cmd, int x, int y, uint8_t handle, uint8_t cell);
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.png b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.png
new file mode 100644
index 0000000..bc46ebe
Binary files /dev/null and b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.png differ
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg
new file mode 100644
index 0000000..78c69c0
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg
@@ -0,0 +1,535 @@
+
+
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbm b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbm
new file mode 100644
index 0000000..39cb670
Binary files /dev/null and b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbm differ
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.png b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.png
new file mode 100644
index 0000000..baafc82
Binary files /dev/null and b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.png differ
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png
new file mode 100644
index 0000000..ef68192
Binary files /dev/null and b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png differ
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg
new file mode 100644
index 0000000..9929649
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg
@@ -0,0 +1,443 @@
+
+
+
+
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.cpp
new file mode 100644
index 0000000..0e251f7
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.cpp
@@ -0,0 +1,46 @@
+/*******************
+ * font_size_t.cpp *
+ *******************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if BOTH(FTDI_EXTENDED, TOUCH_UI_USE_UTF8)
+
+namespace FTDI {
+ // Returns the height of a standard FTDI romfont
+ uint8_t font_size_t::get_romfont_height(uint8_t font) {
+ static const uint8_t tbl[] PROGMEM = {
+ 8, 8, 16, 16, 13, 17, 20, 22, 29, 38, 16, 20, 25, 28, 36, 49, 63, 83, 108
+ };
+ return pgm_read_byte(&tbl[font - 16]);
+ }
+
+ // Sets the scaling coefficient to match a romfont size
+ font_size_t font_size_t::from_romfont(uint8_t font) {
+ return font_size_t(uint32_t(std_height) * 256 / get_romfont_height(font));
+ }
+
+ // Returns the height of the font
+ uint8_t font_size_t::get_height() const {
+ return scale(std_height);
+ }
+}
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.h
new file mode 100644
index 0000000..a2cb8b2
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.h
@@ -0,0 +1,55 @@
+/*****************
+ * font_size_t.h *
+ *****************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+class CommandProcessor;
+
+namespace FTDI {
+
+ /* The unicode rendering of different font sizes happens by scaling a
+ * large-sized font bitmap using the FTDI bitmap transformation matrix.
+ * This keeps us from having to have load bitmaps for all font sizes.
+ *
+ * The font_size_t class helps manage this scaling factor.
+ */
+ class font_size_t {
+ private:
+ // Standard height for font bitmaps
+ static constexpr uint8_t std_height = 49;
+
+ // 8.8 fixed point scaling coefficient
+ uint16_t coefficient;
+
+ font_size_t(uint16_t v) : coefficient(v) {}
+ public:
+ font_size_t() : coefficient(256) {}
+
+ static uint8_t get_romfont_height(uint8_t font);
+
+ static font_size_t from_romfont(uint8_t size);
+
+ template T scale(T val) const {return (int32_t(val) * 256 / coefficient);}
+
+ uint8_t get_height() const;
+ uint16_t get_coefficient() const {return coefficient;}
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.cpp
new file mode 100644
index 0000000..d12bf97
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.cpp
@@ -0,0 +1,107 @@
+/*************************
+ * standard_char_set.cpp *
+ *************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if BOTH(FTDI_EXTENDED, TOUCH_UI_USE_UTF8)
+
+ constexpr static uint8_t std_font = 31;
+
+ /* Lookup table of the char widths for standard ROMFONT 31 */
+
+ uint8_t FTDI::StandardCharSet::std_char_width(char c) {
+ static const uint8_t tbl[] PROGMEM = {
+ 10, 11, 15, 26, 25, 31, 26, 10, 15, 14, 18, 24, 9, 18, 11, 17, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 10, 10, 21, 23, 22, 20, 37, 27, 27, 26,
+ 28, 23, 22, 28, 29, 12, 23, 26, 22, 35, 29, 28, 26, 29, 27, 26, 26, 28,
+ 27, 36, 27, 26, 25, 12, 18, 12, 18, 21, 13, 23, 24, 22, 24, 22, 15, 24,
+ 24, 10, 11, 22, 10, 36, 24, 24, 24, 24, 15, 22, 14, 24, 21, 32, 21, 21,
+ 22, 15, 10, 15, 29, 10
+ };
+ return pgm_read_byte(&tbl[c - ' ']);
+ }
+
+ /**
+ * Load bitmap data into RAMG. This function is called once at the start
+ * of the program.
+ *
+ * Parameters:
+ *
+ * addr - Address in RAMG where the font data is written
+ */
+
+ uint32_t FTDI::StandardCharSet::load_data(uint32_t addr) {
+ return addr;
+ }
+
+ /**
+ * Populates the bitmap handles for the custom into the display list.
+ * This function is called once at the start of each display list.
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ */
+
+ void FTDI::StandardCharSet::load_bitmaps(CommandProcessor& cmd) {
+ CLCD::FontMetrics std_fm(std_font);
+ set_font_bitmap(cmd, std_fm, std_font);
+ }
+
+ /**
+ * Renders a character at location x and y. The x position is incremented
+ * by the width of the character.
+ *
+ * Parameters:
+ *
+ * cmd - If non-NULL the symbol is drawn to the screen.
+ * If NULL, only increment position for text measurement.
+ *
+ * x, y - The location at which to draw the character. On output,
+ * incremented to the location of the next character.
+ *
+ * fs - A scaling object used to scale the font. The display will
+ * already be configured to scale bitmaps, but positions
+ * must be scaled using fs.scale()
+ *
+ * c - The unicode code point to draw. If the renderer does not
+ * support the character, it should draw nothing.
+ */
+
+ bool FTDI::StandardCharSet::render_glyph(CommandProcessor* cmd, int &x, int &y, font_size_t fs, utf8_char_t c) {
+ uint8_t which = (c >= ' ' && c < 128) ? c : '?';
+ uint8_t width = std_char_width(which);
+
+ if (c == '\t') {
+ // Special handling for the tab character
+ which = ' ';
+ width = std_char_width(' ');
+ }
+
+ // Draw the character
+ if (cmd) ext_vertex2ii(*cmd, x, y, std_font, which);
+
+ // Increment X to the next character position
+ x += fs.scale(width);
+ return true;
+ }
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.h
new file mode 100644
index 0000000..48794d4
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.h
@@ -0,0 +1,30 @@
+/***********************
+ * standard_char_set.h *
+ ***********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+namespace FTDI {
+ class StandardCharSet {
+ public:
+ static uint8_t std_char_width(char);
+ static uint32_t load_data(uint32_t addr);
+ static void load_bitmaps(CommandProcessor&);
+ static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t);
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp
new file mode 100644
index 0000000..6f18915
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp
@@ -0,0 +1,247 @@
+/***************
+ * unicode.cpp *
+ ***************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if BOTH(FTDI_EXTENDED, TOUCH_UI_USE_UTF8)
+
+ using namespace FTDI;
+
+ /**
+ * Return true if a string has UTF8 characters
+ *
+ * Parameters:
+ *
+ * c - Pointer to a string.
+ *
+ * Returns: True if the strings has UTF8 characters
+ */
+
+ bool FTDI::has_utf8_chars(const char *str) {
+ for (;;) {
+ const char c = *str++;
+ if (!c) break;
+ if ((c & 0xC0) == 0x80) return true;
+ }
+ return false;
+ }
+
+ bool FTDI::has_utf8_chars(FSTR_P _str) {
+ const char *str = (const char *) _str;
+ for (;;) {
+ const char c = pgm_read_byte(str++);
+ if (!c) break;
+ if ((c & 0xC0) == 0x80) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Return a character in a UTF8 string and increment the
+ * pointer to the next character
+ *
+ * Parameters:
+ *
+ * c - Pointer to a UTF8 encoded string.
+ *
+ * Returns: The packed bytes of a UTF8 encoding of a single
+ * character (this is not the unicode codepoint)
+ */
+
+ utf8_char_t FTDI::get_utf8_char_and_inc(char *&c) {
+ utf8_char_t val = *(uint8_t*)c++;
+ if ((val & 0xC0) == 0xC0)
+ while ((*c & 0xC0) == 0x80)
+ val = (val << 8) | *(uint8_t*)c++;
+ return val;
+ }
+
+ utf8_char_t FTDI::get_utf8_char_and_inc(const char *&c) {
+ utf8_char_t val = *(uint8_t*)c++;
+ if ((val & 0xC0) == 0xC0)
+ while ((*c & 0xC0) == 0x80)
+ val = (val << 8) | *(uint8_t*)c++;
+ return val;
+ }
+
+ /**
+ * Helper function to draw and/or measure a UTF8 string
+ *
+ * Parameters:
+ *
+ * cmd - If non-NULL the symbol is drawn to the screen.
+ * If NULL, only increment position for text measurement.
+ *
+ * x, y - The location at which to draw the string.
+ *
+ * str - The UTF8 string to draw or measure.
+ *
+ * fs - A scaling object used to specify the font size.
+ */
+
+ static uint16_t render_utf8_text(CommandProcessor* cmd, int x, int y, const char *str, font_size_t fs, size_t maxlen=SIZE_MAX) {
+ const int start_x = x;
+ while (*str && maxlen--) {
+ const utf8_char_t c = get_utf8_char_and_inc(str);
+ #ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
+ CyrillicCharSet::render_glyph(cmd, x, y, fs, c) ||
+ #endif
+ #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
+ WesternCharSet::render_glyph(cmd, x, y, fs, c) ||
+ #endif
+ StandardCharSet::render_glyph(cmd, x, y, fs, c);
+ }
+ return x - start_x;
+ }
+
+ /**
+ * Load the font bitmap data into RAMG. Called once at program start.
+ *
+ * Parameters:
+ *
+ * addr - Address in RAMG where the font data is written
+ */
+
+ void FTDI::load_utf8_data(uint32_t addr) {
+ #ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
+ addr = CyrillicCharSet::load_data(addr);
+ #endif
+ #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
+ addr = WesternCharSet::load_data(addr);
+ #endif
+ addr = StandardCharSet::load_data(addr);
+ }
+
+ /**
+ * Populate the bitmap handles for the custom fonts into the display list.
+ * Called once at the start of each display list.
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ */
+
+ void FTDI::load_utf8_bitmaps(CommandProcessor &cmd) {
+ cmd.cmd(SAVE_CONTEXT());
+ #ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
+ CyrillicCharSet::load_bitmaps(cmd);
+ #endif
+ #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
+ WesternCharSet::load_bitmaps(cmd);
+ #endif
+ StandardCharSet::load_bitmaps(cmd);
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+
+ /**
+ * Measure a UTF8 text character
+ *
+ * Parameters:
+ *
+ * c - The unicode code point to measure.
+ *
+ * fs - A scaling object used to specify the font size.
+ *
+ * Returns: A width in pixels
+ */
+
+ uint16_t FTDI::get_utf8_char_width(utf8_char_t c, font_size_t fs) {
+ int x = 0, y = 0;
+ #ifdef TOUCH_UI_UTF8_CYRILLIC_CHARSET
+ CyrillicCharSet::render_glyph(nullptr, x, y, fs, c) ||
+ #endif
+ #ifdef TOUCH_UI_UTF8_WESTERN_CHARSET
+ WesternCharSet::render_glyph(nullptr, x, y, fs, c) ||
+ #endif
+ StandardCharSet::render_glyph(nullptr, x, y, fs, c);
+ return x;
+ }
+
+ /**
+ * Measure a UTF8 text string
+ *
+ * Parameters:
+ *
+ * str - The UTF8 string to measure.
+ *
+ * fs - A scaling object used to specify the font size.
+ *
+ * Returns: A width in pixels
+ */
+
+ uint16_t FTDI::get_utf8_text_width(const char *str, font_size_t fs, size_t maxlen) {
+ return render_utf8_text(nullptr, 0, 0, str, fs, maxlen);
+ }
+
+ uint16_t FTDI::get_utf8_text_width(FSTR_P fstr, font_size_t fs) {
+ #ifdef __AVR__
+ char str[strlen_P(FTOP(fstr)) + 1];
+ strcpy_P(str, FTOP(fstr));
+ return get_utf8_text_width(str, fs);
+ #else
+ return get_utf8_text_width(FTOP(fstr), fs);
+ #endif
+ }
+
+ /**
+ * Draw a UTF8 text string
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ *
+ * x, y - The location at which to draw the string.
+ *
+ * str - The UTF8 string to draw.
+ *
+ * fs - A scaling object used to specify the font size.
+ *
+ * options - Text alignment options (i.e. OPT_CENTERX, OPT_CENTERY, OPT_CENTER or OPT_RIGHTX)
+ *
+ * maxlen - Maximum characters to draw
+ */
+
+ void FTDI::draw_utf8_text(CommandProcessor& cmd, int x, int y, const char *str, font_size_t fs, uint16_t options, size_t maxlen) {
+ cmd.cmd(SAVE_CONTEXT());
+ cmd.cmd(BITMAP_TRANSFORM_A(fs.get_coefficient()));
+ cmd.cmd(BITMAP_TRANSFORM_E(fs.get_coefficient()));
+ cmd.cmd(BEGIN(BITMAPS));
+
+ // Apply alignment options
+ if (options & OPT_CENTERX)
+ x -= get_utf8_text_width(str, fs, maxlen) / 2;
+ else if (options & OPT_RIGHTX)
+ x -= get_utf8_text_width(str, fs, maxlen);
+ if (options & OPT_CENTERY)
+ y -= fs.get_height()/2;
+
+ // Render the text
+ render_utf8_text(&cmd, x, y, str, fs, maxlen);
+ cmd.cmd(RESTORE_CONTEXT());
+ }
+
+ void FTDI::draw_utf8_text(CommandProcessor& cmd, int x, int y, FSTR_P fstr, font_size_t fs, uint16_t options) {
+ char str[strlen_P(FTOP(fstr)) + 1];
+ strcpy_P(str, FTOP(fstr));
+ draw_utf8_text(cmd, x, y, (const char*) str, fs, options);
+ }
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.h
new file mode 100644
index 0000000..7818957
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.h
@@ -0,0 +1,112 @@
+/*************
+ * unicode.h *
+ *************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+class CommandProcessor;
+
+namespace FTDI {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ typedef uint16_t utf8_char_t;
+
+ /**
+ * Converts a 32-bit codepoint into UTF-8. This compile-time function
+ * will be useful until the u8'a' character literal becomes more common.
+ */
+ constexpr uint32_t utf8(const uint32_t c) {
+ return (c < 0x7F ) ? c :
+ (c < 0x7FF) ? (0x0000C080 | ((c & 0b011111000000) << 2) | (c & 0b111111)) :
+ (c < 0xFFFF) ? (0x00E08080 | ((c & 0b001111000000000000) << 4) | ((c & 0b111111000000) << 2) | (c & 0b111111)) :
+ (0xF0808080 | ((c & 0b000111000000000000000000) << 6) | ((c & 0b111111000000000000) << 4) | ((c & 0b111111000000) << 2) | (c & 0b111111));
+ }
+
+ /* Returns true if the string has UTF8 string characters */
+
+ bool has_utf8_chars(FSTR_P str);
+ bool has_utf8_chars(const char *str);
+
+ /* Returns the next character in a UTF8 string and increments the
+ * pointer to the next character */
+
+ utf8_char_t get_utf8_char_and_inc(const char *&c);
+ utf8_char_t get_utf8_char_and_inc(char *&c);
+
+ /* Returns the next character in a UTF8 string, without incrementing */
+
+ inline utf8_char_t get_utf8_char(const char *c) { return get_utf8_char_and_inc(c); }
+
+ void load_utf8_data(uint32_t addr);
+ #else
+ typedef char utf8_char_t;
+
+ inline utf8_char_t get_utf8_char_and_inc(const char *&c) { return *c++; }
+ inline utf8_char_t get_utf8_char(const char *c) { return *c; }
+
+ inline void load_utf8_data(uint32_t) {}
+ #endif
+
+ void load_utf8_bitmaps(CommandProcessor& cmd);
+
+ uint16_t get_utf8_char_width(utf8_char_t, font_size_t);
+ uint16_t get_utf8_text_width(FSTR_P, font_size_t);
+ uint16_t get_utf8_text_width(const char *, font_size_t, size_t maxlen=SIZE_MAX);
+
+ void draw_utf8_text(CommandProcessor&, int x, int y, FSTR_P, font_size_t, uint16_t options = 0);
+ void draw_utf8_text(CommandProcessor&, int x, int y, const char *, font_size_t, uint16_t options = 0, size_t maxlen=SIZE_MAX);
+
+ // Similar to CLCD::FontMetrics, but can be used with UTF8 encoded strings.
+
+ struct FontMetrics {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ font_size_t fs;
+ #else
+ CLCD::FontMetrics fm;
+ #endif
+
+ inline void load(uint8_t rom_font_size) {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ fs = font_size_t::from_romfont(rom_font_size);
+ #else
+ fm.load(rom_font_size);
+ #endif
+ }
+
+ inline uint16_t get_char_width(utf8_char_t c) const {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ return get_utf8_char_width(c, fs);
+ #else
+ return fm.char_widths[(uint8_t)c];
+ #endif
+ }
+
+ inline uint8_t get_height() const {
+ #if ENABLED(TOUCH_UI_USE_UTF8)
+ return fs.get_height();
+ #else
+ return fm.height;
+ #endif
+ }
+
+ inline FontMetrics(uint8_t rom_font_size) {
+ load(rom_font_size);
+ }
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.cpp b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.cpp
new file mode 100644
index 0000000..4fb2f8f
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.cpp
@@ -0,0 +1,455 @@
+/************************
+ * western_char_set.cpp *
+ ************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#include "../ftdi_extended.h"
+
+#if ALL(FTDI_EXTENDED, TOUCH_UI_USE_UTF8, TOUCH_UI_UTF8_WESTERN_CHARSET)
+
+ #include "western_char_set_bitmap_31.h"
+
+ #define NUM_ELEMENTS(a) (sizeof(a)/sizeof(a[0]))
+
+ using namespace FTDI;
+
+ constexpr static uint8_t std_font = 31;
+ constexpr static uint8_t alt_font = 1;
+
+ uint32_t FTDI::WesternCharSet::bitmap_addr;
+
+ /* Glyphs in the WesternCharSet bitmap */
+
+ enum {
+ GRAVE,
+ ACUTE,
+ CIRCUMFLEX,
+ TILDE,
+ DIAERESIS,
+ DOT_ABOVE,
+ CEDILLA,
+ NO_DOT_I,
+ #if ENABLED(TOUCH_UI_UTF8_GERMANIC)
+ SHARP_S,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ LRG_O_STROKE,
+ SML_O_STROKE,
+ LRG_AE,
+ SML_AE,
+ LRG_ETH,
+ SML_ETH,
+ LRG_THORN,
+ SML_THORN,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ LEFT_DBL_QUOTE,
+ RIGHT_DBL_QUOTE,
+ INV_EXCLAMATION,
+ INV_QUESTION,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_CURRENCY)
+ CENT_SIGN,
+ POUND_SIGN,
+ CURRENCY_SIGN,
+ YEN_SIGN,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SUPERSCRIPTS)
+ SUPERSCRIPT_1,
+ SUPERSCRIPT_2,
+ SUPERSCRIPT_3,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_ORDINALS)
+ MASCULINE_ORDINAL,
+ FEMININE_ORDINAL,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_COPYRIGHT)
+ COPYRIGHT_SIGN,
+ REGISTERED_SIGN,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ PLUS_MINUS_SIGN,
+ MULTIPLICATION_SIGN,
+ DIVISION_SIGN,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_FRACTIONS)
+ FRACTION_QUARTER,
+ FRACTION_HALF,
+ FRACTION_THREE_FOURTHS,
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ MICRON_SIGN,
+ PILCROW_SIGN,
+ BROKEN_BAR,
+ SECTION_SIGN,
+ NOT_SIGN
+ #endif
+ };
+
+ /* Centerline of characters that can take accents */
+
+ constexpr int8_t mid_a = 12,
+ mid_e = 12,
+ mid_i = 5,
+ mid_o = 12,
+ mid_u = 12,
+ mid_y = 11,
+ mid_n = 12,
+ mid_c = 12,
+ mid_A = 13,
+ mid_E = 13,
+ mid_I = 6,
+ mid_O = 14,
+ mid_U = 14,
+ mid_Y = 13,
+ mid_N = 15,
+ mid_C = 13;
+
+ /* Centerline of accent glyphs */
+
+ constexpr int8_t mid_accent = 16;
+
+ /* When reusing the DOT_ABOVE accent glyph for the degree sign, we need to trim the leading space */
+ constexpr uint8_t deg_sign_leading = 9;
+
+ /* Look-up table for constructing characters (must be ordered by unicode)
+ *
+ * Characters are either complete symbols from the Western Char Set bitmap,
+ * or they are constructed using a standard letter from the romfont and
+ * drawing an accent from the Western Char Set bitmap over it.
+ */
+
+ #define UTF8(A) uint16_t(utf8(U##A))
+
+ PROGMEM constexpr struct {
+ uint16_t unicode;
+ uint8_t std_char; // Glyph from standard ROMFONT (zero if none)
+ uint8_t alt_char; // Glyph from Western Char Set bitmap
+ uint8_t alt_data; // For accented characters, the centerline; else char width
+ } char_recipe[] = {
+ {0, 0, NO_DOT_I, 10 },
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ {UTF8('¡'), 0 , INV_EXCLAMATION, 13 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_CURRENCY)
+ {UTF8('¢'), 0 , CENT_SIGN, 23 },
+ {UTF8('£'), 0 , POUND_SIGN, 24 },
+ {UTF8('¤'), 0 , CURRENCY_SIGN, 26 },
+ {UTF8('¥'), 0 , YEN_SIGN, 26 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ {UTF8('¦'), 0 , BROKEN_BAR, 11 },
+ {UTF8('§'), 0 , SECTION_SIGN, 21 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_COPYRIGHT)
+ {UTF8('©'), 0 , COPYRIGHT_SIGN, 38 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_ORDINALS)
+ {UTF8('ª'), 0 , FEMININE_ORDINAL, 19 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ {UTF8('«'), 0 , LEFT_DBL_QUOTE, 23 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ {UTF8('¬'), 0 , NOT_SIGN, 32 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_COPYRIGHT)
+ {UTF8('®'), 0 , REGISTERED_SIGN, 38 },
+ #endif
+ {UTF8('°'), 0 , DOT_ABOVE, 24 },
+ #if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ {UTF8('±'), 0 , NOT_SIGN, 32 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SUPERSCRIPTS)
+ {UTF8('²'), 0 , SUPERSCRIPT_2, 16 },
+ {UTF8('³'), 0 , SUPERSCRIPT_3, 16 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ {UTF8('µ'), 0 , MICRON_SIGN, 28 },
+ {UTF8('¶'), 0 , PILCROW_SIGN, 24 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SUPERSCRIPTS)
+ {UTF8('¹'), 0 , SUPERSCRIPT_1, 16 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_ORDINALS)
+ {UTF8('º'), 0 , MASCULINE_ORDINAL, 19 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ {UTF8('»'), 0 , RIGHT_DBL_QUOTE, 24 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_FRACTIONS)
+ {UTF8('¼'), 0 , FRACTION_QUARTER, 40 },
+ {UTF8('½'), 0 , FRACTION_HALF, 40 },
+ {UTF8('¾'), 0 , FRACTION_THREE_FOURTHS, 40 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ {UTF8('¿'), 0 , INV_QUESTION, 21 },
+ #endif
+ {UTF8('À'), 'A', GRAVE, mid_A},
+ {UTF8('Á'), 'A', ACUTE, mid_A},
+ {UTF8('Â'), 'A', CIRCUMFLEX, mid_A},
+ {UTF8('Ã'), 'A', TILDE, mid_A},
+ {UTF8('Ä'), 'A', DIAERESIS, mid_A},
+ {UTF8('Å'), 'A', DOT_ABOVE, mid_A},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('Æ'), 0 , LRG_AE, 40},
+ #endif
+ {UTF8('Ç'), 'C', CEDILLA, mid_C},
+ {UTF8('È'), 'E', GRAVE, mid_E},
+ {UTF8('É'), 'E', ACUTE, mid_E},
+ {UTF8('Ê'), 'E', CIRCUMFLEX, mid_E},
+ {UTF8('Ë'), 'E', DIAERESIS, mid_E},
+ {UTF8('Ì'), 'I', GRAVE, mid_I},
+ {UTF8('Í'), 'I', ACUTE, mid_I},
+ {UTF8('Î'), 'I', CIRCUMFLEX, mid_I},
+ {UTF8('Ï'), 'I', DIAERESIS, mid_I},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('Ð'), 0, LRG_ETH, 31 },
+ #endif
+ {UTF8('Ñ'), 'N', TILDE, mid_N},
+ {UTF8('Ò'), 'O', GRAVE, mid_O},
+ {UTF8('Ó'), 'O', ACUTE, mid_O},
+ {UTF8('Ô'), 'O', CIRCUMFLEX, mid_O},
+ {UTF8('Õ'), 'O', TILDE, mid_O},
+ {UTF8('Ö'), 'O', DIAERESIS, mid_O},
+ #if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ {UTF8('×'), 0 , MULTIPLICATION_SIGN, 32 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('Ø'), 0 , LRG_O_STROKE, 32 },
+ #endif
+ {UTF8('Ù'), 'U', GRAVE, mid_U},
+ {UTF8('Ú'), 'U', ACUTE, mid_U},
+ {UTF8('Û'), 'U', CIRCUMFLEX, mid_U},
+ {UTF8('Ü'), 'U', DIAERESIS, mid_U},
+ {UTF8('Ý'), 'Y', ACUTE, mid_Y},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('Þ'), 0 , LRG_THORN, 25 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_GERMANIC)
+ {UTF8('ß'), 0 , SHARP_S, 26 },
+ #endif
+ {UTF8('à'), 'a', GRAVE, mid_a},
+ {UTF8('á'), 'a', ACUTE, mid_a},
+ {UTF8('â'), 'a', CIRCUMFLEX, mid_a},
+ {UTF8('ã'), 'a', TILDE, mid_a},
+ {UTF8('ä'), 'a', DIAERESIS, mid_a},
+ {UTF8('å'), 'a', DOT_ABOVE, mid_a},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('æ'), 0 , SML_AE, 40 },
+ #endif
+ {UTF8('ç'), 'c', CEDILLA, mid_c},
+ {UTF8('è'), 'e', GRAVE, mid_e},
+ {UTF8('é'), 'e', ACUTE, mid_e},
+ {UTF8('ê'), 'e', CIRCUMFLEX, mid_e},
+ {UTF8('ë'), 'e', DIAERESIS, mid_e},
+ {UTF8('ì'), 'i', GRAVE, mid_i},
+ {UTF8('í'), 'i', ACUTE, mid_i},
+ {UTF8('î'), 'i', CIRCUMFLEX, mid_i},
+ {UTF8('ï'), 'i', DIAERESIS, mid_i},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('ð'), 0, SML_ETH, 24 },
+ #endif
+ {UTF8('ñ'), 'n', TILDE, mid_n},
+ {UTF8('ò'), 'o', GRAVE, mid_o},
+ {UTF8('ó'), 'o', ACUTE, mid_o},
+ {UTF8('ô'), 'o', CIRCUMFLEX, mid_o},
+ {UTF8('õ'), 'o', TILDE, mid_o},
+ {UTF8('ö'), 'o', DIAERESIS, mid_o},
+ #if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ {UTF8('÷'), 0 , DIVISION_SIGN, 32 },
+ #endif
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('ø'), 0 , SML_O_STROKE, 25 },
+ #endif
+ {UTF8('ù'), 'u', GRAVE, mid_u},
+ {UTF8('ú'), 'u', ACUTE, mid_u},
+ {UTF8('û'), 'u', CIRCUMFLEX, mid_u},
+ {UTF8('ü'), 'u', DIAERESIS, mid_u},
+ {UTF8('ý'), 'y', ACUTE, mid_y},
+ #if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ {UTF8('þ'), 0 , SML_THORN, 25 },
+ #endif
+ {UTF8('ÿ'), 'y', DIAERESIS, mid_y},
+ };
+
+ static_assert(UTF8('¡') == 0xC2A1, "Incorrect encoding for character");
+
+ /* Compile-time check that the table is in sorted order */
+
+ constexpr bool is_sorted(size_t n) {
+ return n < 2 ? true : char_recipe[n-2].unicode < char_recipe[n-1].unicode && is_sorted(n-1);
+ }
+
+ static_assert(is_sorted(NUM_ELEMENTS(char_recipe)), "The table must be sorted by unicode value");
+
+ /* Performs a binary search to find a unicode character in the table */
+
+ static int8_t find_char_data(FTDI::utf8_char_t c) {
+ int8_t min = 0, max = NUM_ELEMENTS(char_recipe), index;
+ for (;;) {
+ index = (min + max)/2;
+ const uint16_t char_at = pgm_read_word(&char_recipe[index].unicode);
+ if (char_at == c) break;
+ if (min == max) return -1;
+ if (c > char_at)
+ min = index + 1;
+ else
+ max = index;
+ }
+ return index;
+ }
+
+ static void get_char_data(uint8_t index, uint8_t &std_char, uint8_t &alt_char, uint8_t &alt_data) {
+ std_char = pgm_read_byte(&char_recipe[index].std_char);
+ alt_char = pgm_read_byte(&char_recipe[index].alt_char);
+ alt_data = pgm_read_byte(&char_recipe[index].alt_data);
+ }
+
+ /**
+ * Load bitmap data into RAMG. This function is called once at the start
+ * of the program.
+ *
+ * Parameters:
+ *
+ * addr - Address in RAMG where the font data is written
+ */
+
+ uint32_t FTDI::WesternCharSet::load_data(uint32_t addr) {
+ if (addr % 4 != 0)
+ addr += 4 - (addr % 4);
+
+ // Load the alternative font metrics
+ CLCD::FontMetrics alt_fm;
+ alt_fm.ptr = addr + 148;
+ alt_fm.format = L4;
+ alt_fm.stride = 19;
+ alt_fm.width = 38;
+ alt_fm.height = 49;
+ LOOP_L_N(i, 127)
+ alt_fm.char_widths[i] = 0;
+
+ // For special characters, copy the character widths from the char tables
+ LOOP_L_N(i, NUM_ELEMENTS(char_recipe)) {
+ uint8_t std_char, alt_char, alt_data;
+ get_char_data(i, std_char, alt_char, alt_data);
+ if (std_char == 0)
+ alt_fm.char_widths[alt_char] = alt_data;
+ }
+ CLCD::mem_write_bulk(addr, &alt_fm, 148);
+
+ // Decode the RLE data and load it into RAMG as a bitmap
+ uint32_t lastaddr = write_rle_data(addr + 148, font, sizeof(font));
+
+ bitmap_addr = addr;
+
+ return lastaddr;
+ }
+
+ /**
+ * Populates the bitmap handles for the custom into the display list.
+ * This function is called once at the start of each display list.
+ *
+ * Parameters:
+ *
+ * cmd - Object used for writing to the FTDI chip command queue.
+ */
+
+ void FTDI::WesternCharSet::load_bitmaps(CommandProcessor& cmd) {
+ CLCD::FontMetrics alt_fm;
+ alt_fm.ptr = bitmap_addr + 148;
+ alt_fm.format = L4;
+ alt_fm.stride = 19;
+ alt_fm.width = 38;
+ alt_fm.height = 49;
+ set_font_bitmap(cmd, alt_fm, alt_font);
+ }
+
+ /**
+ * Renders a character at location x and y. The x position is incremented
+ * by the width of the character.
+ *
+ * Parameters:
+ *
+ * cmd - If non-NULL the symbol is drawn to the screen.
+ * If NULL, only increment position for text measurement.
+ *
+ * x, y - The location at which to draw the character. On output,
+ * incremented to the location of the next character.
+ *
+ * fs - A scaling object used to scale the font. The display will
+ * already be configured to scale bitmaps, but positions
+ * must be scaled using fs.scale()
+ *
+ * c - The unicode code point to draw. If the renderer does not
+ * support the character, it should return false.
+ *
+ * Returns: Whether the character was supported.
+ */
+
+ bool FTDI::WesternCharSet::render_glyph(CommandProcessor* cmd, int &x, int &y, font_size_t fs, utf8_char_t c) {
+
+ // A supported character?
+ if (c < UTF8('¡') || c > UTF8('ÿ')) return false;
+
+ int8_t index = find_char_data(c);
+ if (index == -1) return false;
+
+ // Determine character characteristics
+ uint8_t std_char, alt_char, alt_data;
+ get_char_data(index, std_char, alt_char, alt_data);
+
+ bool base_special;
+ uint8_t base_width;
+ uint8_t base_char;
+ uint8_t accent_char;
+ int8_t accent_dx, accent_dy;
+
+ if (std_char == 0) {
+ // Special character, non-accented
+ base_width = alt_data;
+ base_special = true;
+ base_char = alt_char;
+ accent_char = 0;
+ if (c == UTF8('°'))
+ x -= fs.scale(deg_sign_leading);
+ }
+ else {
+ // Regular character with accent:
+ accent_dx = alt_data - mid_accent;
+ accent_dy = isupper(std_char) ? -7 : 0;
+ accent_char = alt_char;
+ base_width = StandardCharSet::std_char_width(std_char);
+ base_special = std_char == 'i';
+ base_char = base_special ? NO_DOT_I : std_char;
+ }
+
+ // If cmd != nullptr, draw the glyph to the screen
+ if (cmd) {
+ ext_vertex2ii(*cmd, x, y, base_special ? alt_font : std_font, base_char);
+ if (accent_char)
+ ext_vertex2ii(*cmd, x + fs.scale(accent_dx), y + fs.scale(accent_dy), alt_font, accent_char);
+ }
+
+ // Increment X to the next character position
+ x += fs.scale(base_width);
+ return true;
+ }
+
+#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8 && TOUCH_UI_UTF8_WESTERN_CHARSET
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.h
new file mode 100644
index 0000000..683093d
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.h
@@ -0,0 +1,31 @@
+/**********************
+ * western_char_set.h *
+ **********************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+namespace FTDI {
+ class WesternCharSet {
+ private:
+ static uint32_t bitmap_addr;
+ public:
+ static uint32_t load_data(uint32_t addr);
+ static void load_bitmaps(CommandProcessor&);
+ static bool render_glyph(CommandProcessor*, int &x, int &y, font_size_t, utf8_char_t);
+ };
+}
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set_bitmap_31.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set_bitmap_31.h
new file mode 100644
index 0000000..3f85cf0
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set_bitmap_31.h
@@ -0,0 +1,1315 @@
+/********************************
+ * western_european_bitmap_31.h *
+ ********************************/
+
+/****************************************************************************
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+/* This is a dump of "font_bitmaps/western_european_bitmap_31.png"
+ * using the tool "bitmap2cpp.py". The tool converts the image into
+ * 16-level grayscale and packs two pixels per byte. The resulting
+ * bytes are then RLE compressed to yield (count, byte) pairs.
+ */
+
+const unsigned char font[] PROGMEM = {
+
+ /* 0 GRAVE */
+ 0x76, 0x00, 0x01, 0x08, 0x01, 0xEE, 0x01, 0xE5, 0x11, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xD0,
+ 0x10, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xF9, 0x11, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF2,
+ 0x11, 0x00, 0x01, 0x5F, 0x01, 0xFD, 0x11, 0x00, 0x01, 0x06, 0x01, 0x99,
+ 0x01, 0x40, 0xFF, 0x00, 0xFF, 0x00, 0xA4, 0x00,
+
+ /* 1 ACUTE */
+ 0x7B, 0x00, 0x01, 0x9E, 0x01, 0xEE, 0x01, 0x50, 0x0F, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF8, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xD1, 0x10, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x01, 0x20, 0x0F, 0x00,
+ 0x01, 0x01, 0x01, 0xEF, 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xAA,
+ 0x01, 0x40, 0xFF, 0x00, 0xFF, 0x00, 0xA5, 0x00,
+
+ /* 2 CIRCUMFLEX */
+ 0x79, 0x00, 0x01, 0xCF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x07, 0x02, 0xFF,
+ 0x01, 0x60, 0x0F, 0x00, 0x01, 0x2F, 0x02, 0xFF, 0x01, 0xF2, 0x0F, 0x00,
+ 0x01, 0xCF, 0x01, 0xF6, 0x01, 0x6F, 0x01, 0xFB, 0x0E, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xA0, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0x60, 0x0D, 0x00,
+ 0x01, 0x1F, 0x01, 0xFD, 0x01, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xF1,
+ 0x0D, 0x00, 0x01, 0xBF, 0x01, 0xF3, 0x02, 0x00, 0x01, 0x3F, 0x01, 0xFB,
+ 0x0C, 0x00, 0x01, 0x02, 0x01, 0x99, 0x01, 0x50, 0x02, 0x00, 0x01, 0x05,
+ 0x01, 0x99, 0x01, 0x20, 0xFF, 0x00, 0xFF, 0x00, 0xA2, 0x00,
+
+ /* 3 TILDE */
+ 0x7C, 0x00, 0x01, 0x11, 0x0D, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xC3,
+ 0x02, 0x00, 0x01, 0xFF, 0x01, 0x80, 0x0C, 0x00, 0x01, 0xAF, 0x02, 0xFF,
+ 0x01, 0x50, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x60, 0x0B, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xD9, 0x01, 0xFF, 0x01, 0xF7, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0x40, 0x0B, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0x20, 0x01, 0x3E,
+ 0x02, 0xFF, 0x01, 0xFD, 0x0C, 0x00, 0x01, 0x09, 0x01, 0xFE, 0x01, 0x00,
+ 0x01, 0x02, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xF4, 0x0C, 0x00, 0x01, 0x07,
+ 0x01, 0xA8, 0x02, 0x00, 0x01, 0x06, 0x01, 0x98, 0x01, 0x20, 0xFF, 0x00,
+ 0xFF, 0x00, 0xB6, 0x00,
+
+ /* 4 DIAERESIS */
+ 0x8A, 0x00, 0x02, 0x44, 0x02, 0x00, 0x02, 0x44, 0x0D, 0x00, 0x02, 0xFF,
+ 0x01, 0x10, 0x01, 0x01, 0x02, 0xFF, 0x0D, 0x00, 0x02, 0xFF, 0x01, 0x10,
+ 0x01, 0x01, 0x02, 0xFF, 0x0D, 0x00, 0x02, 0xFF, 0x01, 0x10, 0x01, 0x01,
+ 0x02, 0xFF, 0x0D, 0x00, 0x02, 0xCC, 0x01, 0x10, 0x01, 0x01, 0x02, 0xCC,
+ 0xFF, 0x00, 0xFF, 0x00, 0xC9, 0x00,
+
+ /* 5 DOT_ABOVE / DEGREE_SIGN */
+ 0x2D, 0x00, 0x01, 0x13, 0x01, 0x30, 0x10, 0x00, 0x01, 0x2B, 0x02, 0xFF,
+ 0x01, 0xA1, 0x0E, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xFD,
+ 0x01, 0x10, 0x0D, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x94, 0x01, 0x5A,
+ 0x01, 0xFF, 0x01, 0xB0, 0x0D, 0x00, 0x01, 0x4F, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x9F, 0x01, 0xF2, 0x0D, 0x00, 0x01, 0x8F, 0x01, 0xF0, 0x02, 0x00,
+ 0x01, 0x2F, 0x01, 0xF6, 0x0D, 0x00, 0x01, 0x8F, 0x01, 0xE0, 0x02, 0x00,
+ 0x01, 0x0F, 0x01, 0xF7, 0x0D, 0x00, 0x01, 0x7F, 0x01, 0xF2, 0x02, 0x00,
+ 0x01, 0x4F, 0x01, 0xF5, 0x0D, 0x00, 0x01, 0x2F, 0x01, 0xFC, 0x01, 0x10,
+ 0x01, 0x02, 0x01, 0xDF, 0x01, 0xF0, 0x0D, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xFB, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x60, 0x0E, 0x00, 0x01, 0x9F,
+ 0x02, 0xFF, 0x01, 0xF8, 0x0F, 0x00, 0x01, 0x03, 0x01, 0x9C, 0x01, 0xC9,
+ 0x01, 0x30, 0xFF, 0x00, 0xFF, 0x00, 0xA4, 0x00,
+
+ /* 6 CEDILLA */
+ 0xFF, 0x00, 0xFF, 0x00, 0xEE, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0x20,
+ 0x11, 0x00, 0x01, 0xCF, 0x01, 0xC0, 0x11, 0x00, 0x01, 0x3F, 0x01, 0xF6,
+ 0x11, 0x00, 0x01, 0x0F, 0x01, 0xFB, 0x11, 0x00, 0x01, 0x3F, 0x01, 0xFD,
+ 0x0E, 0x00, 0x01, 0x07, 0x01, 0xD9, 0x01, 0x89, 0x01, 0xFF, 0x01, 0xFB,
+ 0x0E, 0x00, 0x01, 0x07, 0x03, 0xFF, 0x01, 0xF3, 0x0E, 0x00, 0x01, 0x04,
+ 0x01, 0xBD, 0x01, 0xEE, 0x01, 0xD9, 0x01, 0x20, 0x2F, 0x00,
+
+ /* 7 NO_DOT_I */
+ 0xFF, 0x00, 0x32, 0x00, 0x01, 0x01, 0x01, 0x99, 0x01, 0x96, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xF9, 0x10, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0x10, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF9, 0xCD, 0x00,
+
+#if ENABLED(TOUCH_UI_UTF8_GERMANIC)
+ /* 8 SHARP_S */
+ 0x8A, 0x00, 0x01, 0x35, 0x01, 0x66, 0x01, 0x52, 0x0E, 0x00, 0x01, 0x03,
+ 0x01, 0xAF, 0x03, 0xFF, 0x01, 0xE7, 0x0D, 0x00, 0x01, 0x7F, 0x05, 0xFF,
+ 0x01, 0xC1, 0x0B, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xFC, 0x01, 0xAA,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFC, 0x0B, 0x00, 0x01, 0x2F, 0x01, 0xFF,
+ 0x01, 0xF9, 0x01, 0x10, 0x01, 0x00, 0x01, 0x02, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x70, 0x0A, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x80, 0x03, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xE0, 0x0A, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x04, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF3, 0x09, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xFB, 0x04, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF7,
+ 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x03,
+ 0x01, 0x9E, 0x01, 0xFF, 0x01, 0xF8, 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x02, 0x00, 0x01, 0x01, 0x01, 0xAF, 0x02, 0xFF, 0x01, 0xD7,
+ 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x1D,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x50, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x02, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x70, 0x0B, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x01, 0x01, 0xFF,
+ 0x01, 0xFA, 0x0C, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF4, 0x0C, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x01, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF4, 0x0C, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xF9, 0x0C, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x00,
+ 0x01, 0x02, 0x02, 0xFF, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x02, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xF8, 0x0B, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x1D, 0x02, 0xFF,
+ 0x01, 0xD3, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00,
+ 0x01, 0x01, 0x01, 0xCF, 0x02, 0xFF, 0x01, 0x70, 0x09, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x03, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xFB,
+ 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x2B,
+ 0x02, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8,
+ 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF6, 0x08, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFD,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x10, 0x07, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x08, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xFD,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x02, 0x01, 0x84,
+ 0x03, 0x00, 0x01, 0x2D, 0x01, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xEC, 0x01, 0xA9,
+ 0x01, 0xAC, 0x02, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF8, 0x01, 0x02, 0x05, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x08, 0x00,
+ 0x01, 0x03, 0x01, 0xEE, 0x01, 0xE7, 0x01, 0x01, 0x01, 0xBF, 0x03, 0xFF,
+ 0x01, 0xFE, 0x01, 0x80, 0x0E, 0x00, 0x01, 0x35, 0x01, 0x78, 0x01, 0x76,
+ 0x01, 0x30, 0xB4, 0x00,
+#endif
+
+#if ENABLED(TOUCH_UI_UTF8_SCANDINAVIAN)
+ /* 9 LRG_O_STROKE */
+ 0x93, 0x00, 0x01, 0x40, 0x0A, 0x00, 0x01, 0x47, 0x01, 0x9A, 0x01, 0xBA,
+ 0x01, 0x95, 0x01, 0x10, 0x02, 0x00, 0x01, 0x07, 0x01, 0xF8, 0x08, 0x00,
+ 0x01, 0x02, 0x01, 0xAF, 0x04, 0xFF, 0x01, 0xFC, 0x01, 0x50, 0x01, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x30, 0x07, 0x00, 0x01, 0x8F, 0x06, 0xFF,
+ 0x01, 0xFC, 0x01, 0x23, 0x01, 0xFF, 0x01, 0xF6, 0x07, 0x00, 0x01, 0x1C,
+ 0x03, 0xFF, 0x01, 0xCA, 0x01, 0x9B, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xFE,
+ 0x01, 0xFF, 0x01, 0x80, 0x07, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x50, 0x02, 0x00, 0x01, 0x02, 0x01, 0x9F, 0x02, 0xFF, 0x01, 0xFA,
+ 0x07, 0x00, 0x01, 0x09, 0x02, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x03,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF3, 0x07, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0xF9, 0x06, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xFC, 0x07, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x06, 0x03, 0xFF,
+ 0x01, 0x60, 0x05, 0x00, 0x01, 0x04, 0x02, 0xFF, 0x01, 0x30, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xC0, 0x05, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFC, 0x05, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x01, 0xF7, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xF6, 0x05, 0x00, 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xA0,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF8, 0x05, 0x00, 0x01, 0x3F, 0x01, 0xFF,
+ 0x01, 0xF2, 0x05, 0x00, 0x01, 0xCF, 0x01, 0xFC, 0x01, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xE0,
+ 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xD1, 0x01, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xC0,
+ 0x04, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x20, 0x01, 0x00, 0x01, 0x03,
+ 0x02, 0xFF, 0x05, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF4, 0x02, 0x00, 0x01, 0x02, 0x02, 0xFF,
+ 0x01, 0x10, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0, 0x03, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00, 0x01, 0x01, 0x02, 0xFF,
+ 0x01, 0x30, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0, 0x02, 0x00,
+ 0x01, 0x01, 0x01, 0xEF, 0x01, 0xF8, 0x03, 0x00, 0x01, 0x02, 0x02, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xB0, 0x02, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00, 0x01, 0x03, 0x02, 0xFF,
+ 0x01, 0x10, 0x04, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xC0, 0x02, 0x00,
+ 0x01, 0xBF, 0x01, 0xFD, 0x04, 0x00, 0x01, 0x04, 0x02, 0xFF, 0x05, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xE1, 0x04, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFE, 0x05, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x6F, 0x01, 0xFF,
+ 0x01, 0x30, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xFA, 0x05, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF6, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF5,
+ 0x05, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF7, 0x05, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0x70, 0x05, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF2, 0x05, 0x00, 0x01, 0x03, 0x02, 0xFF,
+ 0x01, 0xEF, 0x01, 0xFA, 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x06, 0x00, 0x01, 0xCF, 0x02, 0xFF, 0x01, 0xC0, 0x05, 0x00, 0x01, 0x06,
+ 0x02, 0xFF, 0x01, 0x40, 0x06, 0x00, 0x01, 0x2F, 0x02, 0xFF, 0x01, 0x20,
+ 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xFB, 0x07, 0x00, 0x01, 0x0B,
+ 0x02, 0xFF, 0x01, 0xD2, 0x04, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0xE1,
+ 0x07, 0x00, 0x01, 0x5F, 0x03, 0xFF, 0x01, 0x93, 0x02, 0x00, 0x01, 0x05,
+ 0x01, 0xCF, 0x02, 0xFF, 0x01, 0x30, 0x06, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xFB, 0x03, 0xFF, 0x01, 0xFD, 0x01, 0xDE, 0x03, 0xFF, 0x01, 0xE3,
+ 0x07, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0x80, 0x01, 0x4D, 0x06, 0xFF,
+ 0x01, 0xFA, 0x01, 0x10, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFB, 0x02, 0x00,
+ 0x01, 0x5C, 0x04, 0xFF, 0x01, 0xE9, 0x01, 0x30, 0x08, 0x00, 0x01, 0x1C,
+ 0x01, 0xD0, 0x03, 0x00, 0x01, 0x04, 0x01, 0x67, 0x01, 0x86, 0x01, 0x53,
+ 0x0B, 0x00, 0x01, 0x10, 0xA8, 0x00,
+
+ /* 10 SML_O_STROKE */
+ 0xFF, 0x00, 0x15, 0x00, 0x01, 0x02, 0x01, 0x20, 0x0C, 0x00, 0x01, 0x02,
+ 0x01, 0x32, 0x01, 0x10, 0x02, 0x00, 0x01, 0x1D, 0x01, 0xE3, 0x0A, 0x00,
+ 0x01, 0x01, 0x01, 0x7C, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0x82, 0x01, 0x00,
+ 0x01, 0xCF, 0x01, 0xF7, 0x0A, 0x00, 0x01, 0x6E, 0x05, 0xFF, 0x01, 0x89,
+ 0x01, 0xFF, 0x01, 0xA0, 0x09, 0x00, 0x01, 0x08, 0x07, 0xFF, 0x01, 0xFC,
+ 0x0A, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x50, 0x01, 0x00,
+ 0x01, 0x3A, 0x02, 0xFF, 0x01, 0xF1, 0x09, 0x00, 0x01, 0x01, 0x02, 0xFF,
+ 0x01, 0x90, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xF5, 0x09, 0x00,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x01, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0xFD, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF3,
+ 0x03, 0x00, 0x01, 0x0B, 0x03, 0xFF, 0x01, 0x30, 0x08, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFA, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0x80, 0x08, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x80,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xC0, 0x01, 0x3F, 0x01, 0xFF,
+ 0x01, 0xB0, 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x50, 0x02, 0x00,
+ 0x01, 0x3F, 0x01, 0xFE, 0x01, 0x10, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xE0,
+ 0x08, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x40, 0x01, 0x00, 0x01, 0x02,
+ 0x01, 0xEF, 0x01, 0xF3, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF0,
+ 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x30, 0x01, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0x50, 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF0,
+ 0x08, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x30, 0x01, 0x00, 0x01, 0xBF,
+ 0x01, 0xF8, 0x02, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xB0,
+ 0x02, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0x60, 0x01, 0x5F, 0x01, 0xFD, 0x03, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xC0, 0x08, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA3,
+ 0x01, 0xFF, 0x01, 0xE2, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x90,
+ 0x08, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0xFF, 0x01, 0x40,
+ 0x03, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x08, 0x00, 0x01, 0x0A,
+ 0x02, 0xFF, 0x01, 0xF6, 0x03, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFE,
+ 0x09, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0xB0, 0x03, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xF8, 0x0A, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xF7,
+ 0x02, 0x00, 0x01, 0x05, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xD0, 0x09, 0x00,
+ 0x01, 0x04, 0x03, 0xFF, 0x01, 0xFC, 0x01, 0xAB, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x20, 0x09, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xAF,
+ 0x05, 0xFF, 0x01, 0xD2, 0x09, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xF5,
+ 0x01, 0x04, 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xD6, 0x0A, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0x70, 0x01, 0x00, 0x01, 0x01, 0x01, 0x46, 0x01, 0x76,
+ 0x01, 0x52, 0x0C, 0x00, 0x01, 0x28, 0xA9, 0x00,
+
+ /* 11 LRG_AE */
+ 0x9E, 0x00, 0x01, 0x14, 0x0B, 0x44, 0x01, 0x41, 0x06, 0x00, 0x01, 0x8F,
+ 0x0B, 0xFF, 0x01, 0xF3, 0x06, 0x00, 0x01, 0xEF, 0x0B, 0xFF, 0x01, 0xF3,
+ 0x05, 0x00, 0x01, 0x05, 0x02, 0xFF, 0x01, 0xEE, 0x09, 0xFF, 0x01, 0xF3,
+ 0x05, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF5, 0x01, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x63, 0x06, 0x33, 0x01, 0x30, 0x05, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x0C, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x80, 0x01, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x10,
+ 0x01, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xFA, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x0B, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF3, 0x02, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xD0,
+ 0x02, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x0A, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFE, 0x03, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x0A, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF9,
+ 0x03, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xED, 0x06, 0xDD, 0x01, 0x80,
+ 0x03, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2, 0x03, 0x00, 0x01, 0xDF,
+ 0x08, 0xFF, 0x01, 0xA0, 0x03, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xB0,
+ 0x03, 0x00, 0x01, 0xDF, 0x08, 0xFF, 0x01, 0xA0, 0x03, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x40, 0x03, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xA8,
+ 0x06, 0x88, 0x01, 0x50, 0x02, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFE,
+ 0x04, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x09, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF4, 0x04, 0x33, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x09, 0x00, 0x01, 0x7F, 0x08, 0xFF, 0x01, 0x40,
+ 0x09, 0x00, 0x01, 0xEF, 0x08, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x05,
+ 0x09, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF7,
+ 0x05, 0x33, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xE0, 0x05, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40,
+ 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x80, 0x05, 0x00, 0x01, 0xDF,
+ 0x01, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x05, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xFB, 0x06, 0x00, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xA8, 0x06, 0x88,
+ 0x01, 0x85, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xF4, 0x06, 0x00, 0x01, 0xDF,
+ 0x08, 0xFF, 0x01, 0xF9, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xE0, 0x06, 0x00,
+ 0x01, 0xDF, 0x08, 0xFF, 0x01, 0xF9, 0x01, 0x8D, 0x01, 0xDD, 0x01, 0x60,
+ 0x06, 0x00, 0x01, 0xBD, 0x08, 0xDD, 0x01, 0xD8, 0xBE, 0x00,
+
+ /* 12 SML_AE */
+ 0xFF, 0x00, 0x22, 0x00, 0x01, 0x01, 0x01, 0x34, 0x01, 0x31, 0x06, 0x00,
+ 0x01, 0x12, 0x01, 0x42, 0x01, 0x10, 0x05, 0x00, 0x01, 0x02, 0x01, 0x7B,
+ 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x60, 0x02, 0x00, 0x01, 0x03,
+ 0x01, 0x9E, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0x81, 0x04, 0x00, 0x01, 0xBF,
+ 0x05, 0xFF, 0x01, 0xFE, 0x01, 0x40, 0x01, 0x01, 0x01, 0x9F, 0x05, 0xFF,
+ 0x01, 0x60, 0x03, 0x00, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xEE, 0x03, 0xFF,
+ 0x01, 0xF5, 0x01, 0x1D, 0x03, 0xFF, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xF8,
+ 0x03, 0x00, 0x01, 0xDF, 0x01, 0xB6, 0x01, 0x30, 0x01, 0x00, 0x01, 0x01,
+ 0x01, 0x5D, 0x02, 0xFF, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xE7, 0x01, 0x20,
+ 0x01, 0x00, 0x01, 0x29, 0x02, 0xFF, 0x01, 0x50, 0x02, 0x00, 0x01, 0x71,
+ 0x05, 0x00, 0x01, 0xAF, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x10, 0x03, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0x0D, 0x02, 0xFF,
+ 0x01, 0xD0, 0x04, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7, 0x08, 0x00,
+ 0x01, 0x06, 0x02, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0xEF, 0x01, 0xFD,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFD, 0x06, 0x00, 0x01, 0x9F,
+ 0x01, 0xFF, 0x04, 0x00, 0x01, 0x02, 0x01, 0x45, 0x02, 0x66, 0x01, 0x67,
+ 0x01, 0xFF, 0x01, 0xF9, 0x06, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x03, 0x00,
+ 0x01, 0x4A, 0x06, 0xFF, 0x01, 0xFB, 0x03, 0x66, 0x01, 0x67, 0x02, 0x77,
+ 0x01, 0xAF, 0x01, 0xFF, 0x02, 0x00, 0x01, 0x1B, 0x10, 0xFF, 0x01, 0x00,
+ 0x01, 0x01, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xCA, 0x01, 0x98, 0x01, 0x88,
+ 0x01, 0x89, 0x0A, 0xFF, 0x01, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x40, 0x03, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFA, 0x08, 0x77,
+ 0x01, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x04, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x09, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x70,
+ 0x04, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFA, 0x09, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFE,
+ 0x09, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0F,
+ 0x02, 0xFF, 0x01, 0x50, 0x08, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x60,
+ 0x04, 0x00, 0x01, 0x8F, 0x02, 0xFF, 0x01, 0xE1, 0x08, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0xD0, 0x03, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x10, 0x05, 0x00, 0x01, 0x45, 0x01, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x20, 0x01, 0x00, 0x01, 0x01,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xA2, 0x02, 0xFF, 0x01, 0xE6, 0x01, 0x10,
+ 0x02, 0x00, 0x01, 0x02, 0x01, 0x8D, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x05,
+ 0x02, 0xFF, 0x01, 0xFD, 0x01, 0xAB, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xFC,
+ 0x01, 0x00, 0x01, 0x3F, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0xBA, 0x01, 0xBC,
+ 0x02, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x7F, 0x05, 0xFF, 0x01, 0xA0,
+ 0x01, 0x00, 0x01, 0x02, 0x01, 0xCF, 0x06, 0xFF, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x03, 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xB4, 0x03, 0x00, 0x01, 0x05,
+ 0x01, 0xBF, 0x04, 0xFF, 0x01, 0xB7, 0x01, 0x10, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0x46, 0x01, 0x76, 0x01, 0x41, 0x06, 0x00, 0x01, 0x35, 0x01, 0x67,
+ 0x01, 0x64, 0x01, 0x20, 0xAD, 0x00,
+
+ /* 13 LRG_ETH */
+ 0x9A, 0x00, 0x01, 0x34, 0x03, 0x44, 0x01, 0x43, 0x01, 0x21, 0x0D, 0x00,
+ 0x01, 0xBF, 0x05, 0xFF, 0x01, 0xFE, 0x01, 0xB8, 0x01, 0x40, 0x0A, 0x00,
+ 0x01, 0xBF, 0x07, 0xFF, 0x01, 0xFE, 0x01, 0x81, 0x09, 0x00, 0x01, 0xBF,
+ 0x08, 0xFF, 0x01, 0xFE, 0x01, 0x60, 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x61, 0x02, 0x11, 0x01, 0x23, 0x01, 0x58, 0x01, 0xCF, 0x02, 0xFF,
+ 0x01, 0xF9, 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x04, 0x00,
+ 0x01, 0x02, 0x01, 0x9F, 0x02, 0xFF, 0x01, 0x80, 0x07, 0x00, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0x50, 0x05, 0x00, 0x01, 0x04, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xF4, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFD, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x06, 0x00, 0x01, 0x06, 0x02, 0xFF, 0x01, 0x50, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xF0, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x07, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xF3, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xF5, 0x04, 0x00, 0x01, 0x23, 0x01, 0x33, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x73, 0x02, 0x33, 0x01, 0x30, 0x04, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xF6, 0x04, 0x00, 0x01, 0xCF, 0x06, 0xFF, 0x01, 0xF2, 0x04, 0x00,
+ 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0xCF, 0x06, 0xFF,
+ 0x01, 0xF2, 0x04, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF9, 0x04, 0x00,
+ 0x01, 0x9B, 0x01, 0xBB, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xDB, 0x02, 0xBB,
+ 0x01, 0xB1, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xF7, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00,
+ 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF6, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x07, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF4, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0xF1, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xD0, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x06, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x80, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00, 0x01, 0x0B, 0x02, 0xFF,
+ 0x01, 0x20, 0x06, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x06, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xF9, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF,
+ 0x01, 0x50, 0x05, 0x00, 0x01, 0x0A, 0x02, 0xFF, 0x01, 0xE1, 0x07, 0x00,
+ 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x50, 0x04, 0x00, 0x01, 0x29, 0x03, 0xFF,
+ 0x01, 0x30, 0x07, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xA7, 0x01, 0x77,
+ 0x01, 0x78, 0x01, 0x9A, 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xE3, 0x08, 0x00,
+ 0x01, 0xBF, 0x08, 0xFF, 0x01, 0xF9, 0x01, 0x10, 0x08, 0x00, 0x01, 0xBF,
+ 0x07, 0xFF, 0x01, 0xD8, 0x01, 0x10, 0x09, 0x00, 0x01, 0xAD, 0x03, 0xDD,
+ 0x01, 0xDC, 0x01, 0xCB, 0x01, 0xA7, 0x01, 0x41, 0xC7, 0x00,
+
+ /* 14 SML_ETH */
+ 0x88, 0x00, 0x01, 0x38, 0x01, 0x88, 0x01, 0x81, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x5A, 0x01, 0x40, 0x0C, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xB0, 0x01, 0x04, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0xA0, 0x0C, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0xFC, 0x02, 0xFF,
+ 0x01, 0xD8, 0x01, 0x20, 0x0C, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xFD,
+ 0x01, 0x82, 0x0D, 0x00, 0x01, 0x5A, 0x03, 0xFF, 0x01, 0xF4, 0x0D, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x87, 0x02, 0xFF, 0x01, 0x30,
+ 0x0C, 0x00, 0x01, 0x6F, 0x01, 0xE9, 0x01, 0x30, 0x01, 0x00, 0x01, 0x8F,
+ 0x01, 0xFF, 0x01, 0xE2, 0x0C, 0x00, 0x01, 0x03, 0x03, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x10, 0x0E, 0x00, 0x01, 0x23, 0x01, 0x44,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0x02, 0x01, 0x9E,
+ 0x04, 0xFF, 0x01, 0xF7, 0x0C, 0x00, 0x01, 0x7F, 0x06, 0xFF, 0x01, 0x30,
+ 0x0A, 0x00, 0x01, 0x09, 0x02, 0xFF, 0x01, 0xFE, 0x01, 0xCB, 0x01, 0xDF,
+ 0x02, 0xFF, 0x01, 0xD0, 0x0A, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xFB,
+ 0x01, 0x30, 0x02, 0x00, 0x01, 0x4E, 0x01, 0xFF, 0x01, 0xF5, 0x09, 0x00,
+ 0x01, 0x02, 0x02, 0xFF, 0x01, 0x70, 0x03, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xFD, 0x09, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFA, 0x05, 0x00,
+ 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x20, 0x08, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xF1, 0x05, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA0, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0xB0, 0x08, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x70, 0x05, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF,
+ 0x01, 0x40, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x30, 0x05, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x01, 0xF0, 0x08, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x30, 0x05, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFF,
+ 0x01, 0x40, 0x05, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x70, 0x05, 0x00, 0x01, 0x2F, 0x01, 0xFF,
+ 0x01, 0xD0, 0x08, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA0, 0x05, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x90, 0x08, 0x00, 0x01, 0x0F, 0x01, 0xFF,
+ 0x01, 0xF1, 0x05, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x08, 0x00,
+ 0x01, 0x09, 0x01, 0xFF, 0x01, 0xF9, 0x04, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xFE, 0x09, 0x00, 0x01, 0x02, 0x02, 0xFF, 0x01, 0x60, 0x03, 0x00,
+ 0x01, 0x3E, 0x01, 0xFF, 0x01, 0xF6, 0x0A, 0x00, 0x01, 0x7F, 0x01, 0xFF,
+ 0x01, 0xF9, 0x01, 0x20, 0x01, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0xB0,
+ 0x0A, 0x00, 0x01, 0x09, 0x02, 0xFF, 0x01, 0xFD, 0x01, 0xBD, 0x02, 0xFF,
+ 0x01, 0xFD, 0x01, 0x10, 0x0B, 0x00, 0x01, 0x7F, 0x05, 0xFF, 0x01, 0xB0,
+ 0x0C, 0x00, 0x01, 0x02, 0x01, 0xAE, 0x03, 0xFF, 0x01, 0xB4, 0x0F, 0x00,
+ 0x01, 0x35, 0x01, 0x65, 0x01, 0x40, 0xB6, 0x00,
+
+ /* 15 LRG_THORN */
+ 0x9A, 0x00, 0x02, 0x55, 0x11, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x05, 0xFF, 0x01, 0xED, 0x01, 0xA7, 0x01, 0x10, 0x0B, 0x00, 0x07, 0xFF,
+ 0x01, 0xFA, 0x01, 0x10, 0x0A, 0x00, 0x08, 0xFF, 0x01, 0xE2, 0x0A, 0x00,
+ 0x02, 0xFF, 0x01, 0x65, 0x01, 0x55, 0x01, 0x56, 0x01, 0x7A, 0x02, 0xFF,
+ 0x01, 0xFE, 0x01, 0x10, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x03, 0x00,
+ 0x01, 0x1B, 0x02, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20,
+ 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xF0, 0x09, 0x00, 0x02, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF3, 0x09, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF6,
+ 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0xF7, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0xF7, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x04, 0x00,
+ 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF6, 0x09, 0x00, 0x02, 0xFF, 0x01, 0x20,
+ 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF3, 0x09, 0x00, 0x02, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0xF0, 0x09, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x1B, 0x02, 0xFF, 0x01, 0x80,
+ 0x09, 0x00, 0x02, 0xFF, 0x01, 0x65, 0x02, 0x55, 0x01, 0x7A, 0x02, 0xFF,
+ 0x01, 0xFE, 0x01, 0x10, 0x09, 0x00, 0x08, 0xFF, 0x01, 0xE2, 0x0A, 0x00,
+ 0x07, 0xFF, 0x01, 0xFA, 0x01, 0x10, 0x0A, 0x00, 0x05, 0xFF, 0x01, 0xED,
+ 0x01, 0xA7, 0x01, 0x10, 0x0B, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00,
+ 0x02, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x02, 0xCC, 0x01, 0x10, 0xCC, 0x00,
+
+ /* 16 SML_THORN */
+ 0x86, 0x00, 0x01, 0x02, 0x01, 0x99, 0x01, 0x94, 0x10, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7,
+ 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7,
+ 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7,
+ 0x02, 0x00, 0x01, 0x13, 0x01, 0x54, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x01, 0x00, 0x01, 0x5C, 0x02, 0xFF, 0x01, 0xFD,
+ 0x01, 0x70, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x01, 0x0B,
+ 0x04, 0xFF, 0x01, 0xFD, 0x01, 0x20, 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF7, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xEC, 0x01, 0xDF, 0x02, 0xFF,
+ 0x01, 0xE1, 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0xFF,
+ 0x01, 0xC3, 0x02, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xFC, 0x09, 0x00,
+ 0x01, 0x03, 0x02, 0xFF, 0x01, 0xFA, 0x03, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x60, 0x08, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x01, 0xE0,
+ 0x04, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x03,
+ 0x02, 0xFF, 0x01, 0x60, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF3,
+ 0x08, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x05, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF7, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFC, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFB, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF9, 0x06, 0x00, 0x01, 0xFF, 0x01, 0xFD, 0x08, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xFE, 0x08, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xEF,
+ 0x01, 0xFE, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF9, 0x06, 0x00,
+ 0x01, 0xFF, 0x01, 0xFD, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFC,
+ 0x05, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFB, 0x08, 0x00, 0x01, 0x03,
+ 0x02, 0xFF, 0x05, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF8, 0x08, 0x00,
+ 0x01, 0x03, 0x02, 0xFF, 0x01, 0x60, 0x04, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xF3, 0x08, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x01, 0xD0, 0x04, 0x00,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xD0, 0x08, 0x00, 0x01, 0x03, 0x02, 0xFF,
+ 0x01, 0xFA, 0x03, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x60,
+ 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0xFF, 0x01, 0xB3,
+ 0x02, 0x00, 0x01, 0x6E, 0x01, 0xFF, 0x01, 0xFC, 0x09, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0xEC, 0x01, 0xCF,
+ 0x02, 0xFF, 0x01, 0xE2, 0x09, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7,
+ 0x01, 0x0B, 0x04, 0xFF, 0x01, 0xFD, 0x01, 0x20, 0x09, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF7, 0x01, 0x00, 0x01, 0x6C, 0x02, 0xFF, 0x01, 0xFE,
+ 0x01, 0x70, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x23, 0x01, 0x54, 0x01, 0x20, 0x0B, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x03, 0x01, 0xFF,
+ 0x01, 0xF7, 0x10, 0x00, 0x01, 0x01, 0x01, 0x66, 0x01, 0x63, 0x22, 0x00,
+#endif // TOUCH_UI_UTF8_SCANDINAVIAN
+
+#if ENABLED(TOUCH_UI_UTF8_PUNCTUATION)
+ /* 17 LEFT_DBL_QUOTE */
+ 0xFF, 0x00, 0x4A, 0x00, 0x01, 0x30, 0x03, 0x00, 0x01, 0x02, 0x0D, 0x00,
+ 0x01, 0x08, 0x01, 0xA0, 0x02, 0x00, 0x01, 0x01, 0x01, 0xC6, 0x0D, 0x00,
+ 0x01, 0xAF, 0x01, 0xA0, 0x02, 0x00, 0x01, 0x1D, 0x01, 0xF6, 0x0C, 0x00,
+ 0x01, 0x1C, 0x01, 0xFF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x02, 0x01, 0xEF,
+ 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x50,
+ 0x01, 0x00, 0x01, 0x3E, 0x01, 0xFF, 0x01, 0xE2, 0x0B, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xF4, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x20, 0x0A, 0x00, 0x01, 0x04, 0x01, 0xEF, 0x01, 0xFE, 0x01, 0x30,
+ 0x01, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xD1, 0x0B, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0xD2, 0x01, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFB,
+ 0x0B, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x10, 0x01, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x0C, 0x01, 0xFF,
+ 0x01, 0xD0, 0x02, 0x00, 0x01, 0xFF, 0x01, 0xFA, 0x0C, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x50,
+ 0x0C, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x1C,
+ 0x01, 0xFF, 0x01, 0xF6, 0x0C, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFB,
+ 0x02, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x90, 0x0C, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xD1, 0x01, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xFA,
+ 0x0C, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x20, 0x01, 0x00,
+ 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0xA0, 0x01, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF6, 0x0C, 0x00,
+ 0x01, 0x02, 0x01, 0xEF, 0x01, 0xA0, 0x02, 0x00, 0x01, 0x5F, 0x01, 0xF6,
+ 0x0D, 0x00, 0x01, 0x1D, 0x01, 0xA0, 0x02, 0x00, 0x01, 0x04, 0x01, 0xE6,
+ 0x0D, 0x00, 0x01, 0x01, 0x01, 0x60, 0x03, 0x00, 0x01, 0x24, 0xFF, 0x00,
+
+ /* 18 RIGHT_DBL_QUOTE */
+ 0xFF, 0x00, 0x46, 0x00, 0x01, 0x20, 0x03, 0x00, 0x01, 0x20, 0x0D, 0x00,
+ 0x01, 0x01, 0x01, 0xE3, 0x03, 0x00, 0x01, 0x5D, 0x01, 0x10, 0x0C, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0x50, 0x02, 0x00, 0x01, 0x5F, 0x01, 0xE2,
+ 0x0C, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF6, 0x02, 0x00, 0x01, 0x5F,
+ 0x01, 0xFE, 0x01, 0x30, 0x0C, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x80,
+ 0x01, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xF5, 0x0C, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xFA, 0x01, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x60, 0x0C, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xB0, 0x01, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF9, 0x0C, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xFC, 0x01, 0x10, 0x01, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xA0,
+ 0x0C, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xD1, 0x01, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF5,
+ 0x02, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x10, 0x0B, 0x00, 0x01, 0x2D,
+ 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x10, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0x40,
+ 0x01, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xD2, 0x0B, 0x00, 0x01, 0x4F,
+ 0x01, 0xFF, 0x01, 0xE3, 0x01, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFC,
+ 0x01, 0x10, 0x0A, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x10,
+ 0x01, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x01, 0xC1, 0x01, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF9,
+ 0x0B, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0x70, 0x0B, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0x90,
+ 0x02, 0x00, 0x01, 0x5F, 0x01, 0xF6, 0x0C, 0x00, 0x01, 0x01, 0x01, 0xF8,
+ 0x03, 0x00, 0x01, 0x5F, 0x01, 0x40, 0x0C, 0x00, 0x01, 0x01, 0x01, 0x50,
+ 0x03, 0x00, 0x01, 0x43, 0xFF, 0x00, 0x04, 0x00,
+
+ /* 19 INV_EXCLAMATION */
+ 0xFF, 0x00, 0x34, 0x00, 0x01, 0xAD, 0x01, 0xDD, 0x01, 0x40, 0x10, 0x00,
+ 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00,
+ 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x34, 0x01, 0x44,
+ 0x01, 0x10, 0x49, 0x00, 0x01, 0x02, 0x01, 0x22, 0x11, 0x00, 0x01, 0x6F,
+ 0x01, 0xFF, 0x11, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x11, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0x10, 0x10, 0x00, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x20,
+ 0x10, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x30, 0x10, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x30, 0x10, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x40,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50,
+ 0x10, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x34,
+ 0x01, 0x44, 0x01, 0x10, 0x33, 0x00,
+
+ /* 20 INV_QUESTION */
+ 0xFF, 0x00, 0x36, 0x00, 0x02, 0xDD, 0x11, 0x00, 0x02, 0xFF, 0x11, 0x00,
+ 0x02, 0xFF, 0x11, 0x00, 0x02, 0xFF, 0x11, 0x00, 0x02, 0xFF, 0x11, 0x00,
+ 0x02, 0x44, 0x37, 0x00, 0x01, 0xBC, 0x01, 0xCB, 0x11, 0x00, 0x01, 0xEF,
+ 0x01, 0xFE, 0x11, 0x00, 0x01, 0xEF, 0x01, 0xFE, 0x11, 0x00, 0x01, 0xEF,
+ 0x01, 0xFE, 0x11, 0x00, 0x01, 0xFF, 0x01, 0xFD, 0x10, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xFB, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xD0, 0x0F, 0x00, 0x01, 0x0A,
+ 0x02, 0xFF, 0x01, 0x30, 0x0F, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xF4,
+ 0x0F, 0x00, 0x01, 0x09, 0x02, 0xFF, 0x01, 0x40, 0x0F, 0x00, 0x01, 0x7F,
+ 0x01, 0xFF, 0x01, 0xF4, 0x0F, 0x00, 0x01, 0x03, 0x02, 0xFF, 0x01, 0x40,
+ 0x0F, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF8, 0x10, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x0F, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x05, 0x01, 0xD0, 0x0A, 0x00,
+ 0x01, 0x08, 0x02, 0xFF, 0x01, 0x70, 0x02, 0x00, 0x01, 0x05, 0x01, 0xCF,
+ 0x01, 0xF0, 0x0A, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x98, 0x01, 0x8B, 0x02, 0xFF, 0x01, 0xF0, 0x0B, 0x00, 0x01, 0x3F,
+ 0x06, 0xFF, 0x01, 0xC0, 0x0B, 0x00, 0x01, 0x02, 0x01, 0xCF, 0x04, 0xFF,
+ 0x01, 0xC5, 0x0D, 0x00, 0x01, 0x03, 0x01, 0x8B, 0x01, 0xCC, 0x01, 0xB9,
+ 0x01, 0x62, 0x31, 0x00,
+#endif // TOUCH_UI_UTF8_PUNCTUATION
+
+#if ENABLED(TOUCH_UI_UTF8_CURRENCY)
+ /* 21 CENT_SIGN */
+ 0xB1, 0x00, 0x01, 0x01, 0x01, 0x32, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB,
+ 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB,
+ 0x11, 0x00, 0x01, 0x05, 0x01, 0xFC, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFC,
+ 0x11, 0x00, 0x01, 0x39, 0x01, 0xFD, 0x01, 0x42, 0x0E, 0x00, 0x01, 0x05,
+ 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xFB, 0x01, 0x50, 0x0B, 0x00, 0x01, 0x03,
+ 0x01, 0xCF, 0x05, 0xFF, 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x4F, 0x02, 0xFF,
+ 0x02, 0xFE, 0x01, 0xCE, 0x01, 0xFF, 0x01, 0xF6, 0x0A, 0x00, 0x01, 0x02,
+ 0x02, 0xFF, 0x01, 0xE6, 0x01, 0x05, 0x01, 0xFC, 0x01, 0x00, 0x01, 0x38,
+ 0x01, 0xE6, 0x0A, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x10,
+ 0x01, 0x05, 0x01, 0xFC, 0x02, 0x00, 0x01, 0x02, 0x0A, 0x00, 0x01, 0x5F,
+ 0x01, 0xFF, 0x01, 0xE1, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFC, 0x0D, 0x00,
+ 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x60, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFC,
+ 0x0D, 0x00, 0x02, 0xFF, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFC, 0x0C, 0x00,
+ 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFB, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFC,
+ 0x0C, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x05,
+ 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7, 0x02, 0x00,
+ 0x01, 0x05, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF6,
+ 0x02, 0x00, 0x01, 0x05, 0x01, 0xFC, 0x0C, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF7, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF9, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x0C, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFC, 0x02, 0x00, 0x01, 0x05, 0x01, 0xFB,
+ 0x0D, 0x00, 0x02, 0xFF, 0x01, 0x10, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFB,
+ 0x0D, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0x80, 0x01, 0x00, 0x01, 0x05,
+ 0x01, 0xFB, 0x0D, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x00,
+ 0x01, 0x05, 0x01, 0xFB, 0x0D, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x30, 0x01, 0x05, 0x01, 0xFB, 0x02, 0x00, 0x01, 0x33, 0x0A, 0x00,
+ 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0x35, 0x01, 0xFB,
+ 0x01, 0x02, 0x01, 0x6C, 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x2D, 0x06, 0xFF,
+ 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x01, 0x01, 0x9F, 0x05, 0xFF, 0x01, 0xF5,
+ 0x0C, 0x00, 0x01, 0x02, 0x01, 0x8D, 0x03, 0xFF, 0x01, 0xC7, 0x01, 0x20,
+ 0x0E, 0x00, 0x01, 0x06, 0x01, 0xFC, 0x01, 0x20, 0x10, 0x00, 0x01, 0x05,
+ 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05,
+ 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05, 0x01, 0xFB, 0x11, 0x00, 0x01, 0x05,
+ 0x01, 0xFB, 0x57, 0x00,
+
+ /* 22 POUND_SIGN */
+ 0x9E, 0x00, 0x01, 0x6B, 0x01, 0xDF, 0x01, 0xFD, 0x01, 0xC9, 0x01, 0x40,
+ 0x0D, 0x00, 0x01, 0x6E, 0x05, 0xFF, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x07,
+ 0x06, 0xFF, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0xFE,
+ 0x01, 0x85, 0x01, 0x34, 0x01, 0x7B, 0x01, 0xFF, 0x01, 0x30, 0x0B, 0x00,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xC1, 0x03, 0x00, 0x01, 0x18, 0x01, 0x30,
+ 0x0A, 0x00, 0x01, 0x01, 0x02, 0xFF, 0x01, 0x30, 0x0F, 0x00, 0x01, 0x04,
+ 0x01, 0xFF, 0x01, 0xFD, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xFA,
+ 0x10, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF8, 0x10, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xF7, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x0E, 0x00, 0x01, 0x0A,
+ 0x07, 0xFF, 0x01, 0xF4, 0x0A, 0x00, 0x01, 0x0A, 0x07, 0xFF, 0x01, 0xF4,
+ 0x0A, 0x00, 0x01, 0x08, 0x01, 0xDD, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFE,
+ 0x03, 0xDD, 0x01, 0xD4, 0x0C, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6,
+ 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF6, 0x0E, 0x00, 0x01, 0x4B, 0x01, 0xBB, 0x01, 0xBE,
+ 0x01, 0xFF, 0x01, 0xFD, 0x05, 0xBB, 0x01, 0x70, 0x08, 0x00, 0x01, 0x6F,
+ 0x09, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x6F, 0x09, 0xFF, 0x01, 0xA0,
+ 0x08, 0x00, 0x01, 0x4A, 0x09, 0xAA, 0x01, 0x60, 0xC5, 0x00,
+
+ /* 23 CURRENCY_SIGN */
+ 0xFF, 0x00, 0x0D, 0x00, 0x01, 0x30, 0x07, 0x00, 0x01, 0x01, 0x01, 0x40,
+ 0x08, 0x00, 0x01, 0x0B, 0x01, 0xF5, 0x07, 0x00, 0x01, 0x1D, 0x01, 0xF4,
+ 0x08, 0x00, 0x01, 0xBF, 0x01, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x01,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x30, 0x07, 0x00, 0x01, 0x5F, 0x01, 0xFF,
+ 0x01, 0xF4, 0x01, 0x00, 0x01, 0x6B, 0x01, 0xDD, 0x01, 0xC8, 0x01, 0x20,
+ 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xFA, 0x08, 0x00, 0x01, 0x05, 0x02, 0xFF,
+ 0x01, 0x8E, 0x03, 0xFF, 0x01, 0xFA, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xA0,
+ 0x09, 0x00, 0x01, 0x5F, 0x07, 0xFF, 0x01, 0xFA, 0x0A, 0x00, 0x01, 0x05,
+ 0x02, 0xFF, 0x01, 0xE9, 0x01, 0x55, 0x01, 0x7C, 0x02, 0xFF, 0x01, 0xA0,
+ 0x0A, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x10, 0x02, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xA0, 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0xC0, 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF2, 0x0A, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0xDF, 0x01, 0xF7,
+ 0x0A, 0x00, 0x01, 0x4F, 0x01, 0xFD, 0x05, 0x00, 0x01, 0x8F, 0x01, 0xFA,
+ 0x0A, 0x00, 0x01, 0x6F, 0x01, 0xFC, 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFC,
+ 0x0A, 0x00, 0x01, 0x5F, 0x01, 0xFC, 0x05, 0x00, 0x01, 0x7F, 0x01, 0xFB,
+ 0x0A, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x10, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0xF8, 0x0A, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0x80, 0x03, 0x00,
+ 0x01, 0x03, 0x01, 0xFF, 0x01, 0xF3, 0x0A, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF5, 0x03, 0x00, 0x01, 0x1D, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00,
+ 0x01, 0x01, 0x02, 0xFF, 0x01, 0x92, 0x01, 0x00, 0x01, 0x16, 0x01, 0xEF,
+ 0x01, 0xFF, 0x01, 0x60, 0x0A, 0x00, 0x01, 0x1D, 0x03, 0xFF, 0x01, 0xFE,
+ 0x03, 0xFF, 0x01, 0xF4, 0x09, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x05, 0xFF,
+ 0x01, 0xFE, 0x02, 0xFF, 0x01, 0x40, 0x08, 0x00, 0x01, 0x1D, 0x01, 0xFF,
+ 0x01, 0xFA, 0x01, 0x06, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x81,
+ 0x01, 0x5F, 0x01, 0xFF, 0x01, 0xF4, 0x08, 0x00, 0x01, 0xCF, 0x01, 0xFF,
+ 0x01, 0xA0, 0x01, 0x00, 0x01, 0x01, 0x01, 0x44, 0x01, 0x20, 0x01, 0x00,
+ 0x01, 0x05, 0x02, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0x4F, 0x01, 0xFA,
+ 0x07, 0x00, 0x01, 0x4F, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x05, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x05, 0x01, 0x80, 0xEB, 0x00,
+
+ /* 24 YEN_SIGN */
+ 0x98, 0x00, 0x01, 0x01, 0x01, 0x88, 0x01, 0x85, 0x07, 0x00, 0x01, 0x38,
+ 0x01, 0x88, 0x01, 0x40, 0x07, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10,
+ 0x06, 0x00, 0x01, 0xCF, 0x01, 0xFF, 0x01, 0x10, 0x07, 0x00, 0x01, 0x3F,
+ 0x01, 0xFF, 0x01, 0x90, 0x05, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xF8,
+ 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF2, 0x05, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0xE0, 0x08, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xFA,
+ 0x05, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x60, 0x09, 0x00, 0x01, 0xAF,
+ 0x01, 0xFF, 0x01, 0x30, 0x04, 0x00, 0x01, 0xEF, 0x01, 0xFD, 0x0A, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF5, 0x0A, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF4, 0x03, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xC0, 0x0A, 0x00, 0x01, 0x01, 0x01, 0xEF,
+ 0x01, 0xFD, 0x03, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x40, 0x0B, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x50, 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xE0, 0x01, 0x00,
+ 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF3, 0x0C, 0x00, 0x01, 0x06, 0x01, 0xFF,
+ 0x01, 0xF7, 0x01, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xA0, 0x0A, 0x00,
+ 0x01, 0x2A, 0x02, 0xAA, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x10, 0x01, 0xBF,
+ 0x01, 0xFF, 0x01, 0xCA, 0x01, 0xAA, 0x01, 0xA5, 0x08, 0x00, 0x01, 0x4F,
+ 0x04, 0xFF, 0x01, 0x83, 0x04, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x3C,
+ 0x02, 0xCC, 0x01, 0xCE, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0xFF, 0x01, 0xFC,
+ 0x02, 0xCC, 0x01, 0xC6, 0x0B, 0x00, 0x01, 0x03, 0x03, 0xFF, 0x01, 0x70,
+ 0x0F, 0x00, 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xFE, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xF5, 0x0C, 0x00, 0x01, 0x01, 0x03, 0x11, 0x01, 0x1E,
+ 0x01, 0xFF, 0x01, 0xF3, 0x03, 0x11, 0x01, 0x10, 0x08, 0x00, 0x01, 0x4F,
+ 0x09, 0xFF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x4F, 0x09, 0xFF, 0x01, 0xF8,
+ 0x08, 0x00, 0x01, 0x27, 0x03, 0x77, 0x01, 0x7E, 0x01, 0xFF, 0x01, 0xF8,
+ 0x03, 0x77, 0x01, 0x73, 0x0C, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2,
+ 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2,
+ 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2,
+ 0x10, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x08,
+ 0x01, 0x99, 0x01, 0x91, 0xC9, 0x00,
+#endif // TOUCH_UI_UTF8_CURRENCY
+
+#if ENABLED(TOUCH_UI_UTF8_SUPERSCRIPTS)
+ /* 25 SUPERSCRIPT_ONE */
+ 0x99, 0x00, 0x01, 0x01, 0x01, 0x36, 0x01, 0x9B, 0x01, 0xBB, 0x01, 0x20,
+ 0x0E, 0x00, 0x01, 0x3F, 0x03, 0xFF, 0x01, 0x20, 0x0E, 0x00, 0x01, 0x3F,
+ 0x01, 0xFE, 0x01, 0xBE, 0x01, 0xFF, 0x01, 0x20, 0x0E, 0x00, 0x01, 0x14,
+ 0x01, 0x10, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x10, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x0F, 0x00, 0x01, 0x11, 0x01, 0x1C, 0x01, 0xFF,
+ 0x01, 0x31, 0x01, 0x11, 0x0D, 0x00, 0x01, 0x0D, 0x05, 0xFF, 0x01, 0x40,
+ 0x0C, 0x00, 0x01, 0x0D, 0x05, 0xFF, 0x01, 0x40, 0x0C, 0x00, 0x01, 0x01,
+ 0x05, 0x22, 0xFF, 0x00, 0xC2, 0x00,
+
+ /* 26 SUPERSCRIPT_TWO */
+ 0x88, 0x00, 0x01, 0x01, 0x10, 0x00, 0x01, 0x16, 0x01, 0xAE, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x92, 0x0E, 0x00, 0x05, 0xFF, 0x01, 0x60, 0x0D, 0x00,
+ 0x01, 0xFE, 0x01, 0x84, 0x01, 0x22, 0x01, 0x5C, 0x01, 0xFF, 0x01, 0xF3,
+ 0x0D, 0x00, 0x01, 0x50, 0x03, 0x00, 0x01, 0xCF, 0x01, 0xFA, 0x11, 0x00,
+ 0x01, 0x5F, 0x01, 0xFC, 0x11, 0x00, 0x01, 0x5F, 0x01, 0xFB, 0x11, 0x00,
+ 0x01, 0xCF, 0x01, 0xF4, 0x10, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x6F, 0x01, 0xFE, 0x01, 0x10, 0x0F, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xE2, 0x10, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x01, 0x30,
+ 0x0F, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xE3, 0x10, 0x00, 0x01, 0x6F,
+ 0x01, 0xFE, 0x01, 0x20, 0x0F, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xD1,
+ 0x10, 0x00, 0x01, 0xAF, 0x01, 0xFD, 0x01, 0x43, 0x03, 0x33, 0x0C, 0x00,
+ 0x01, 0x01, 0x06, 0xFF, 0x0C, 0x00, 0x01, 0x01, 0x06, 0xFF, 0x0D, 0x00,
+ 0x06, 0x22, 0xFF, 0x00, 0xC2, 0x00,
+
+ /* 27 SUPERSCRIPT_THREE */
+ 0x88, 0x00, 0x01, 0x01, 0x01, 0x10, 0x0F, 0x00, 0x01, 0x39, 0x01, 0xCE,
+ 0x02, 0xFF, 0x01, 0xB5, 0x0E, 0x00, 0x01, 0x7F, 0x04, 0xFF, 0x01, 0xB0,
+ 0x0D, 0x00, 0x01, 0x6B, 0x01, 0x73, 0x01, 0x22, 0x01, 0x38, 0x01, 0xFF,
+ 0x01, 0xF9, 0x11, 0x00, 0x01, 0x5F, 0x01, 0xFF, 0x11, 0x00, 0x01, 0x0F,
+ 0x01, 0xFF, 0x11, 0x00, 0x01, 0x4F, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x27,
+ 0x01, 0xFF, 0x01, 0xF3, 0x0E, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0xFA,
+ 0x01, 0x20, 0x0E, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0xFB, 0x01, 0x40,
+ 0x0E, 0x00, 0x01, 0x01, 0x01, 0x23, 0x01, 0x49, 0x01, 0xFF, 0x01, 0xF6,
+ 0x11, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x10, 0x10, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x50, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0x60,
+ 0x10, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0x40, 0x0C, 0x00, 0x01, 0xA4,
+ 0x02, 0x00, 0x01, 0x05, 0x01, 0xDF, 0x01, 0xFD, 0x0D, 0x00, 0x02, 0xFF,
+ 0x01, 0xDE, 0x02, 0xFF, 0x01, 0xE3, 0x0D, 0x00, 0x01, 0xAE, 0x03, 0xFF,
+ 0x01, 0xE9, 0x01, 0x10, 0x0E, 0x00, 0x01, 0x24, 0x01, 0x55, 0x01, 0x52,
+ 0xFF, 0x00, 0xC4, 0x00,
+#endif // TOUCH_UI_UTF8_SUPERSCRIPTS
+
+#if ENABLED(TOUCH_UI_UTF8_ORDINALS)
+ /* 28 MASCULINE_ORDINAL */
+ 0x89, 0x00, 0x01, 0x01, 0x01, 0x10, 0x0F, 0x00, 0x01, 0x01, 0x01, 0x8D,
+ 0x02, 0xFF, 0x01, 0xB4, 0x0E, 0x00, 0x01, 0x4F, 0x04, 0xFF, 0x01, 0xA0,
+ 0x0C, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x63, 0x01, 0x48,
+ 0x01, 0xFF, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xA0,
+ 0x02, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x60, 0x0B, 0x00, 0x01, 0x6F,
+ 0x01, 0xFE, 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xD0, 0x0B, 0x00,
+ 0x01, 0xBF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0xFF, 0x01, 0xF2, 0x0B, 0x00,
+ 0x01, 0xEF, 0x01, 0xF3, 0x04, 0x00, 0x01, 0xCF, 0x01, 0xF6, 0x0B, 0x00,
+ 0x01, 0xFF, 0x01, 0xF1, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xF7, 0x0B, 0x00,
+ 0x01, 0xFF, 0x01, 0xF1, 0x04, 0x00, 0x01, 0xAF, 0x01, 0xF7, 0x0B, 0x00,
+ 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xBF, 0x01, 0xF6, 0x0B, 0x00,
+ 0x01, 0xCF, 0x01, 0xF6, 0x04, 0x00, 0x01, 0xEF, 0x01, 0xF4, 0x0B, 0x00,
+ 0x01, 0x8F, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xF0,
+ 0x0B, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00, 0x01, 0x1D,
+ 0x01, 0xFF, 0x01, 0x90, 0x0B, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xF8,
+ 0x01, 0x10, 0x01, 0x04, 0x01, 0xDF, 0x01, 0xFE, 0x01, 0x10, 0x0C, 0x00,
+ 0x01, 0xAF, 0x04, 0xFF, 0x01, 0xE3, 0x0D, 0x00, 0x01, 0x05, 0x01, 0xDF,
+ 0x02, 0xFF, 0x01, 0xFA, 0x01, 0x10, 0x0E, 0x00, 0x01, 0x02, 0x01, 0x56,
+ 0x01, 0x64, 0x21, 0x00, 0x01, 0x16, 0x06, 0x66, 0x01, 0x40, 0x0B, 0x00,
+ 0x01, 0x3F, 0x06, 0xFF, 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x3F, 0x06, 0xFF,
+ 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x01, 0x06, 0x11, 0xFF, 0x00, 0x75, 0x00,
+
+ /* 29 FEMININE_ORDINAL */
+ 0x89, 0x00, 0x01, 0x12, 0x01, 0x10, 0x0F, 0x00, 0x01, 0x49, 0x01, 0xDF,
+ 0x02, 0xFF, 0x01, 0xB4, 0x0D, 0x00, 0x01, 0x07, 0x05, 0xFF, 0x01, 0xA0,
+ 0x0C, 0x00, 0x01, 0x07, 0x01, 0xFC, 0x01, 0x74, 0x01, 0x33, 0x01, 0x59,
+ 0x01, 0xFF, 0x01, 0xF8, 0x0C, 0x00, 0x01, 0x03, 0x01, 0x20, 0x03, 0x00,
+ 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x10, 0x10, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0x50, 0x0E, 0x00, 0x01, 0x01, 0x01, 0x11, 0x01, 0x16, 0x01, 0xFF,
+ 0x01, 0x80, 0x0C, 0x00, 0x01, 0x05, 0x01, 0xAE, 0x04, 0xFF, 0x01, 0x90,
+ 0x0B, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x05, 0xFF, 0x01, 0xA0, 0x0B, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0xE9, 0x01, 0x65, 0x01, 0x44, 0x01, 0x48,
+ 0x01, 0xFF, 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x5F, 0x01, 0xFD, 0x01, 0x10,
+ 0x02, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x9F,
+ 0x01, 0xF6, 0x03, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xA0, 0x0B, 0x00,
+ 0x01, 0xAF, 0x01, 0xF5, 0x03, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x01, 0xA0,
+ 0x0B, 0x00, 0x01, 0x9F, 0x01, 0xFA, 0x03, 0x00, 0x01, 0xAF, 0x01, 0xFF,
+ 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0xA2, 0x01, 0x00,
+ 0x01, 0x3B, 0x02, 0xFF, 0x01, 0xA0, 0x0B, 0x00, 0x01, 0x0A, 0x04, 0xFF,
+ 0x01, 0xE7, 0x01, 0xFF, 0x01, 0xA0, 0x0C, 0x00, 0x01, 0x8F, 0x02, 0xFF,
+ 0x01, 0xF9, 0x01, 0x15, 0x01, 0xFF, 0x01, 0xA0, 0x0D, 0x00, 0x01, 0x46,
+ 0x01, 0x64, 0x02, 0x00, 0x01, 0x11, 0x1F, 0x00, 0x01, 0x16, 0x06, 0x66,
+ 0x01, 0x40, 0x0B, 0x00, 0x01, 0x3F, 0x06, 0xFF, 0x01, 0xB0, 0x0B, 0x00,
+ 0x01, 0x3F, 0x06, 0xFF, 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x01, 0x06, 0x11,
+ 0xFF, 0x00, 0x75, 0x00,
+#endif // TOUCH_UI_UTF8_ORDINALS
+
+#if ENABLED(TOUCH_UI_UTF8_COPYRIGHT)
+ /* 30 COPYRIGHT_SIGN */
+ 0xA0, 0x00, 0x01, 0x01, 0x01, 0x45, 0x01, 0x76, 0x01, 0x43, 0x0E, 0x00,
+ 0x01, 0x28, 0x01, 0xDF, 0x03, 0xFF, 0x01, 0xE9, 0x01, 0x40, 0x0B, 0x00,
+ 0x01, 0x19, 0x02, 0xFF, 0x01, 0xDB, 0x01, 0xAB, 0x01, 0xCE, 0x01, 0xFF,
+ 0x01, 0xFB, 0x01, 0x30, 0x09, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFB,
+ 0x01, 0x50, 0x03, 0x00, 0x01, 0x38, 0x01, 0xFF, 0x01, 0xF7, 0x09, 0x00,
+ 0x01, 0x6F, 0x01, 0xFC, 0x01, 0x30, 0x05, 0x00, 0x01, 0x19, 0x01, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00,
+ 0x01, 0x5F, 0x01, 0xFB, 0x07, 0x00, 0x01, 0x3F, 0x01, 0xF8, 0x03, 0x00,
+ 0x01, 0x46, 0x01, 0x88, 0x01, 0x65, 0x01, 0x10, 0x01, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0x80, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xA0, 0x01, 0x00,
+ 0x01, 0x01, 0x01, 0x9F, 0x03, 0xFF, 0x01, 0xFC, 0x01, 0x60, 0x01, 0x00,
+ 0x01, 0x4F, 0x01, 0xF4, 0x05, 0x00, 0x01, 0x08, 0x01, 0xFD, 0x02, 0x00,
+ 0x01, 0x4E, 0x02, 0xFF, 0x01, 0xED, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x01, 0x00, 0x01, 0x08, 0x01, 0xFD, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xF4,
+ 0x01, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x61, 0x01, 0x00,
+ 0x01, 0x01, 0x01, 0x4A, 0x01, 0xA0, 0x02, 0x00, 0x01, 0xEF, 0x01, 0x60,
+ 0x04, 0x00, 0x01, 0x6F, 0x01, 0xC0, 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x01, 0xC1, 0x07, 0x00, 0x01, 0x7F, 0x01, 0xB0, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0x60, 0x01, 0x00, 0x01, 0x7F, 0x01, 0xFF, 0x01, 0x10, 0x07, 0x00,
+ 0x01, 0x1F, 0x01, 0xF0, 0x04, 0x00, 0x01, 0xFF, 0x01, 0x20, 0x01, 0x00,
+ 0x01, 0xDF, 0x01, 0xF9, 0x08, 0x00, 0x01, 0x0D, 0x01, 0xF4, 0x03, 0x00,
+ 0x01, 0x01, 0x01, 0xFE, 0x01, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF4,
+ 0x08, 0x00, 0x01, 0x0A, 0x01, 0xF6, 0x03, 0x00, 0x01, 0x03, 0x01, 0xFD,
+ 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0x08,
+ 0x01, 0xF8, 0x03, 0x00, 0x01, 0x04, 0x01, 0xFC, 0x01, 0x00, 0x01, 0x03,
+ 0x01, 0xFF, 0x01, 0xF0, 0x08, 0x00, 0x01, 0x07, 0x01, 0xF9, 0x03, 0x00,
+ 0x01, 0x03, 0x01, 0xFD, 0x01, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF1,
+ 0x08, 0x00, 0x01, 0x08, 0x01, 0xF8, 0x03, 0x00, 0x01, 0x01, 0x01, 0xFE,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF3, 0x08, 0x00, 0x01, 0x09,
+ 0x01, 0xF7, 0x04, 0x00, 0x01, 0xFF, 0x01, 0x10, 0x01, 0x00, 0x01, 0xDF,
+ 0x01, 0xF8, 0x08, 0x00, 0x01, 0x0C, 0x01, 0xF5, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0x60, 0x01, 0x00, 0x01, 0x8F, 0x01, 0xFE, 0x01, 0x10, 0x07, 0x00,
+ 0x01, 0x1F, 0x01, 0xF1, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xB0, 0x01, 0x00,
+ 0x01, 0x1F, 0x01, 0xFF, 0x01, 0xB0, 0x07, 0x00, 0x01, 0x6F, 0x01, 0xC0,
+ 0x04, 0x00, 0x01, 0x1F, 0x01, 0xF4, 0x01, 0x00, 0x01, 0x05, 0x01, 0xFF,
+ 0x01, 0xFD, 0x01, 0x50, 0x02, 0x00, 0x01, 0x29, 0x01, 0xA0, 0x02, 0x00,
+ 0x01, 0xEF, 0x01, 0x60, 0x04, 0x00, 0x01, 0x08, 0x01, 0xFD, 0x02, 0x00,
+ 0x01, 0x6F, 0x02, 0xFF, 0x01, 0xDB, 0x01, 0xCE, 0x01, 0xFF, 0x01, 0xB0,
+ 0x01, 0x00, 0x01, 0x07, 0x01, 0xFD, 0x05, 0x00, 0x01, 0x01, 0x01, 0xEF,
+ 0x01, 0x90, 0x01, 0x00, 0x01, 0x02, 0x01, 0xBF, 0x03, 0xFF, 0x01, 0xFE,
+ 0x01, 0x70, 0x01, 0x00, 0x01, 0x4F, 0x01, 0xF4, 0x06, 0x00, 0x01, 0x4F,
+ 0x01, 0xF7, 0x02, 0x00, 0x01, 0x01, 0x01, 0x58, 0x01, 0x9A, 0x01, 0x86,
+ 0x01, 0x30, 0x01, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0x80, 0x06, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0x90, 0x07, 0x00, 0x01, 0x4F, 0x01, 0xFB,
+ 0x08, 0x00, 0x01, 0x6F, 0x01, 0xFC, 0x01, 0x30, 0x05, 0x00, 0x01, 0x18,
+ 0x01, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x04, 0x01, 0xEF, 0x01, 0xFA,
+ 0x01, 0x40, 0x03, 0x00, 0x01, 0x27, 0x01, 0xEF, 0x01, 0xF8, 0x0A, 0x00,
+ 0x01, 0x19, 0x02, 0xFF, 0x01, 0xCA, 0x01, 0x9A, 0x01, 0xBE, 0x01, 0xFF,
+ 0x01, 0xFC, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x29, 0x01, 0xDF, 0x03, 0xFF,
+ 0x01, 0xFA, 0x01, 0x40, 0x0D, 0x00, 0x01, 0x02, 0x01, 0x46, 0x01, 0x76,
+ 0x01, 0x53, 0xC5, 0x00,
+
+ /* 31 REGISTERED_SIGN */
+ 0xA0, 0x00, 0x01, 0x02, 0x01, 0x46, 0x01, 0x76, 0x01, 0x53, 0x0E, 0x00,
+ 0x01, 0x28, 0x01, 0xDF, 0x03, 0xFF, 0x01, 0xEA, 0x01, 0x40, 0x0B, 0x00,
+ 0x01, 0x19, 0x02, 0xFF, 0x01, 0xCB, 0x01, 0x9A, 0x01, 0xCE, 0x01, 0xFF,
+ 0x01, 0xFC, 0x01, 0x30, 0x09, 0x00, 0x01, 0x04, 0x01, 0xEF, 0x01, 0xFA,
+ 0x01, 0x40, 0x03, 0x00, 0x01, 0x38, 0x01, 0xFF, 0x01, 0xF8, 0x09, 0x00,
+ 0x01, 0x6F, 0x01, 0xFC, 0x01, 0x30, 0x05, 0x00, 0x01, 0x18, 0x01, 0xFF,
+ 0x01, 0xA0, 0x07, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0x90, 0x07, 0x00,
+ 0x01, 0x4F, 0x01, 0xFB, 0x07, 0x00, 0x01, 0x3F, 0x01, 0xF7, 0x01, 0x00,
+ 0x01, 0x13, 0x02, 0x33, 0x01, 0x32, 0x03, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0x80, 0x06, 0x00, 0x01, 0xEF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x7F,
+ 0x03, 0xFF, 0x01, 0xFD, 0x01, 0x81, 0x02, 0x00, 0x01, 0x4F, 0x01, 0xF5,
+ 0x05, 0x00, 0x01, 0x08, 0x01, 0xFD, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFF,
+ 0x01, 0xDD, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x30, 0x01, 0x00,
+ 0x01, 0x08, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x1F, 0x01, 0xF4, 0x02, 0x00,
+ 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x3C, 0x01, 0xFF, 0x01, 0xD0,
+ 0x02, 0x00, 0x01, 0xEF, 0x01, 0x60, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xC0,
+ 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF3, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xB0, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0x60, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x03, 0x00, 0x01, 0xFF,
+ 0x01, 0xF4, 0x02, 0x00, 0x01, 0x1F, 0x01, 0xF0, 0x04, 0x00, 0x01, 0xFF,
+ 0x01, 0x10, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x03, 0x00, 0x01, 0xFF,
+ 0x01, 0xF2, 0x02, 0x00, 0x01, 0x0C, 0x01, 0xF5, 0x03, 0x00, 0x01, 0x01,
+ 0x01, 0xFE, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xE0, 0x02, 0x00, 0x01, 0x0A, 0x01, 0xF6, 0x03, 0x00,
+ 0x01, 0x03, 0x01, 0xFD, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFD, 0x01, 0x88,
+ 0x01, 0x9A, 0x01, 0xEF, 0x01, 0xFE, 0x01, 0x30, 0x02, 0x00, 0x01, 0x08,
+ 0x01, 0xF8, 0x03, 0x00, 0x01, 0x04, 0x01, 0xFC, 0x03, 0x00, 0x01, 0x7F,
+ 0x03, 0xFF, 0x01, 0xFE, 0x01, 0x91, 0x03, 0x00, 0x01, 0x07, 0x01, 0xF9,
+ 0x03, 0x00, 0x01, 0x03, 0x01, 0xFD, 0x03, 0x00, 0x01, 0x7F, 0x01, 0xFC,
+ 0x01, 0x78, 0x01, 0xDF, 0x01, 0xFD, 0x01, 0x20, 0x03, 0x00, 0x01, 0x08,
+ 0x01, 0xF8, 0x03, 0x00, 0x01, 0x01, 0x01, 0xFE, 0x03, 0x00, 0x01, 0x7F,
+ 0x01, 0xFA, 0x01, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xC0, 0x03, 0x00,
+ 0x01, 0x09, 0x01, 0xF6, 0x04, 0x00, 0x01, 0xFF, 0x01, 0x10, 0x02, 0x00,
+ 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xF8, 0x03, 0x00,
+ 0x01, 0x0C, 0x01, 0xF5, 0x04, 0x00, 0x01, 0xBF, 0x01, 0x60, 0x02, 0x00,
+ 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x30,
+ 0x02, 0x00, 0x01, 0x1F, 0x01, 0xF1, 0x04, 0x00, 0x01, 0x6F, 0x01, 0xC0,
+ 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x09, 0x01, 0xFF,
+ 0x01, 0xD0, 0x02, 0x00, 0x01, 0x6F, 0x01, 0xB0, 0x04, 0x00, 0x01, 0x1F,
+ 0x01, 0xF4, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x02, 0x00, 0x01, 0x01,
+ 0x01, 0xEF, 0x01, 0xF7, 0x02, 0x00, 0x01, 0xEF, 0x01, 0x60, 0x04, 0x00,
+ 0x01, 0x08, 0x01, 0xFD, 0x02, 0x00, 0x01, 0x7F, 0x01, 0xFA, 0x03, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x20, 0x01, 0x08, 0x01, 0xFE, 0x06, 0x00,
+ 0x01, 0xEF, 0x01, 0xA0, 0x01, 0x00, 0x01, 0x5A, 0x01, 0xA6, 0x03, 0x00,
+ 0x01, 0x09, 0x01, 0xAA, 0x01, 0x60, 0x01, 0x4F, 0x01, 0xF4, 0x06, 0x00,
+ 0x01, 0x3F, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x03, 0x01, 0xFF, 0x01, 0x80,
+ 0x06, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0x90, 0x07, 0x00, 0x01, 0x4F,
+ 0x01, 0xFB, 0x08, 0x00, 0x01, 0x6F, 0x01, 0xFC, 0x01, 0x30, 0x05, 0x00,
+ 0x01, 0x19, 0x01, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x04, 0x01, 0xEF,
+ 0x01, 0xFA, 0x01, 0x40, 0x03, 0x00, 0x01, 0x38, 0x01, 0xEF, 0x01, 0xF8,
+ 0x0A, 0x00, 0x01, 0x19, 0x02, 0xFF, 0x01, 0xCB, 0x01, 0x9A, 0x01, 0xCE,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x30, 0x0B, 0x00, 0x01, 0x28, 0x01, 0xDF,
+ 0x03, 0xFF, 0x01, 0xEA, 0x01, 0x40, 0x0D, 0x00, 0x01, 0x02, 0x01, 0x45,
+ 0x01, 0x76, 0x01, 0x43, 0xC5, 0x00,
+#endif // TOUCH_UI_UTF8_COPYRIGHT
+
+#if ENABLED(TOUCH_UI_UTF8_MATHEMATICS)
+ /* 32 PLUS_MINUS_SIGN */
+ 0xEB, 0x00, 0x01, 0x02, 0x01, 0x77, 0x01, 0x70, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x0B, 0x00, 0x01, 0x6A, 0x04, 0xAA, 0x01, 0xAC,
+ 0x01, 0xFF, 0x01, 0xFA, 0x05, 0xAA, 0x01, 0x20, 0x05, 0x00, 0x01, 0x9F,
+ 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40,
+ 0x05, 0x00, 0x01, 0x7C, 0x04, 0xCC, 0x01, 0xCD, 0x01, 0xFF, 0x01, 0xFC,
+ 0x05, 0xCC, 0x01, 0x30, 0x0A, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF0,
+ 0x10, 0x00, 0x01, 0x03, 0x01, 0x99, 0x01, 0x90, 0x44, 0x00, 0x01, 0x9F,
+ 0x0C, 0xFF, 0x01, 0x30, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40,
+ 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x47,
+ 0x0C, 0x77, 0x01, 0x10, 0xC1, 0x00,
+
+ /* 33 MULTIPLICATION_SIGN */
+ 0xFF, 0x00, 0x0E, 0x00, 0x01, 0x09, 0x01, 0xB0, 0x07, 0x00, 0x01, 0x03,
+ 0x01, 0xE4, 0x08, 0x00, 0x01, 0x9F, 0x01, 0xFB, 0x07, 0x00, 0x01, 0x3E,
+ 0x01, 0xFF, 0x01, 0x40, 0x06, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x05, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xA0,
+ 0x07, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x3E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x08, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x03, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x09, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB, 0x03, 0x00, 0x01, 0x3E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x0A, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB0, 0x01, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0,
+ 0x0B, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x3E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x0C, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB3, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x0D, 0x00, 0x01, 0x3E,
+ 0x03, 0xFF, 0x01, 0xFB, 0x0E, 0x00, 0x01, 0x03, 0x01, 0xEF, 0x02, 0xFF,
+ 0x01, 0xB0, 0x0F, 0x00, 0x01, 0x5F, 0x02, 0xFF, 0x01, 0x10, 0x0E, 0x00,
+ 0x01, 0x03, 0x01, 0xEF, 0x02, 0xFF, 0x01, 0xB0, 0x0E, 0x00, 0x01, 0x3E,
+ 0x03, 0xFF, 0x01, 0xFB, 0x0D, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xB3, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB,
+ 0x0B, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x01, 0x00,
+ 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x0A, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x03, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB,
+ 0x09, 0x00, 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x03, 0x00,
+ 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x08, 0x00, 0x01, 0x2E,
+ 0x01, 0xFF, 0x01, 0xFB, 0x05, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0xFB,
+ 0x07, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xB0, 0x05, 0x00,
+ 0x01, 0x02, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xA0, 0x07, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x07, 0x00, 0x01, 0x2E, 0x01, 0xFF, 0x01, 0x40, 0x07, 0x00,
+ 0x01, 0x09, 0x01, 0xB0, 0x07, 0x00, 0x01, 0x02, 0x01, 0xE4, 0xE9, 0x00,
+
+ /* 34 DIVISION_SIGN */
+ 0xFF, 0x00, 0x25, 0x00, 0x01, 0x17, 0x01, 0x77, 0x01, 0x76, 0x10, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF,
+ 0x01, 0xFC, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x17, 0x01, 0x77,
+ 0x01, 0x76, 0x31, 0x00, 0x01, 0x24, 0x0C, 0x44, 0x01, 0x10, 0x05, 0x00,
+ 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF,
+ 0x01, 0x40, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00,
+ 0x01, 0x12, 0x0C, 0x22, 0x31, 0x00, 0x01, 0x18, 0x01, 0x88, 0x01, 0x87,
+ 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC,
+ 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0xFC, 0x10, 0x00, 0x01, 0x16,
+ 0x01, 0x66, 0x01, 0x65, 0xFF, 0x00, 0x01, 0x00,
+#endif // TOUCH_UI_UTF8_MATHEMATICS
+
+#if ENABLED(TOUCH_UI_UTF8_FRACTIONS)
+ /* 35 FRACTION_QUARTER */
+ 0x92, 0x00, 0x01, 0x01, 0x01, 0x44, 0x01, 0x40, 0x04, 0x00, 0x01, 0x04,
+ 0x01, 0x79, 0x01, 0xCE, 0x01, 0xEE, 0x01, 0x20, 0x07, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0x90, 0x04, 0x00, 0x01, 0x3F, 0x03, 0xFF, 0x01, 0x20,
+ 0x07, 0x00, 0x01, 0x3F, 0x01, 0xFE, 0x01, 0x10, 0x04, 0x00, 0x01, 0x3F,
+ 0x01, 0xDB, 0x01, 0x8D, 0x01, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0xDF,
+ 0x01, 0xF5, 0x05, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x20, 0x06, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x06, 0x00, 0x01, 0x1F, 0x01, 0xFF,
+ 0x01, 0x20, 0x07, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x06, 0x00,
+ 0x01, 0xAF, 0x01, 0xF8, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x05, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE1, 0x08, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50,
+ 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x7F,
+ 0x01, 0xFC, 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00,
+ 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF2, 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFE,
+ 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0xDF,
+ 0x01, 0xF5, 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xB0, 0x04, 0x00, 0x01, 0x37, 0x01, 0x77,
+ 0x02, 0x00, 0x01, 0x04, 0x01, 0x55, 0x01, 0x5D, 0x01, 0xFF, 0x01, 0x75,
+ 0x01, 0x55, 0x01, 0x10, 0x01, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x20,
+ 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0xFF, 0x02, 0x00, 0x01, 0x0D,
+ 0x05, 0xFF, 0x01, 0x40, 0x01, 0x00, 0x01, 0xAF, 0x01, 0xF8, 0x04, 0x00,
+ 0x01, 0x0C, 0x02, 0xFF, 0x02, 0x00, 0x01, 0x0C, 0x05, 0xEE, 0x01, 0x40,
+ 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE0, 0x04, 0x00, 0x01, 0x8F, 0x01, 0xBE,
+ 0x01, 0xFF, 0x09, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50, 0x03, 0x00,
+ 0x01, 0x04, 0x01, 0xFE, 0x01, 0x1E, 0x01, 0xFF, 0x09, 0x00, 0x01, 0x7F,
+ 0x01, 0xFC, 0x04, 0x00, 0x01, 0x1E, 0x01, 0xF4, 0x01, 0x0E, 0x01, 0xFF,
+ 0x08, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xBF,
+ 0x01, 0x80, 0x01, 0x0E, 0x01, 0xFF, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x80, 0x03, 0x00, 0x01, 0x08, 0x01, 0xFC, 0x01, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x08, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x04, 0x00, 0x01, 0x4F,
+ 0x01, 0xE1, 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x08, 0x00, 0x01, 0xDF,
+ 0x01, 0xF5, 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0x40, 0x01, 0x00,
+ 0x01, 0x0E, 0x01, 0xFF, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xB0,
+ 0x03, 0x00, 0x01, 0x0B, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x07, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x3F,
+ 0x01, 0xF8, 0x02, 0x88, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0x88, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x4F, 0x06, 0xFF, 0x05, 0x00,
+ 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE0, 0x04, 0x00, 0x01, 0x2A, 0x03, 0xAA,
+ 0x01, 0xAF, 0x01, 0xFF, 0x01, 0xAA, 0x05, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0x50, 0x08, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x06, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF2, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x05, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0x05, 0x01, 0x66,
+ 0xBF, 0x00,
+
+ /* 36 FRACTION_HALF */
+ 0x92, 0x00, 0x01, 0x01, 0x01, 0x44, 0x01, 0x40, 0x04, 0x00, 0x01, 0x04,
+ 0x01, 0x7A, 0x01, 0xCE, 0x01, 0xEE, 0x01, 0x20, 0x07, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0x80, 0x04, 0x00, 0x01, 0x3F, 0x03, 0xFF, 0x01, 0x20,
+ 0x07, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x3F, 0x01, 0xDA,
+ 0x01, 0x7D, 0x01, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0xDF, 0x01, 0xF5,
+ 0x07, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x06, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x06, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x01, 0x20, 0x07, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x06, 0x00, 0x01, 0xAF, 0x01, 0xF8, 0x08, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x04, 0x01, 0xFF,
+ 0x01, 0xE0, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00,
+ 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x20, 0x05, 0x00, 0x01, 0x7F, 0x01, 0xFC, 0x09, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF2,
+ 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20, 0x04, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0x80, 0x09, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x20,
+ 0x04, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x0A, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x20, 0x04, 0x00, 0x01, 0xDF, 0x01, 0xF5, 0x0A, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xB0,
+ 0x01, 0x00, 0x01, 0x04, 0x01, 0x8A, 0x01, 0xCC, 0x01, 0xA7, 0x01, 0x10,
+ 0x02, 0x00, 0x01, 0x04, 0x01, 0x55, 0x01, 0x5D, 0x01, 0xFF, 0x01, 0x75,
+ 0x01, 0x55, 0x01, 0x10, 0x01, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x20,
+ 0x01, 0x06, 0x04, 0xFF, 0x01, 0xF7, 0x02, 0x00, 0x01, 0x0D, 0x05, 0xFF,
+ 0x01, 0x40, 0x01, 0x00, 0x01, 0xBF, 0x01, 0xF8, 0x01, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xA7, 0x01, 0x68, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0x70,
+ 0x01, 0x00, 0x01, 0x0B, 0x05, 0xDD, 0x01, 0x40, 0x01, 0x04, 0x01, 0xFF,
+ 0x01, 0xE0, 0x01, 0x00, 0x01, 0x05, 0x01, 0x60, 0x02, 0x00, 0x01, 0x08,
+ 0x01, 0xFF, 0x01, 0xF1, 0x08, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50,
+ 0x06, 0x00, 0x01, 0xEF, 0x01, 0xF4, 0x08, 0x00, 0x01, 0x7F, 0x01, 0xFB,
+ 0x07, 0x00, 0x01, 0xCF, 0x01, 0xF3, 0x07, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF2, 0x06, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xE0, 0x07, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x80, 0x06, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0x50, 0x07, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x07, 0x00, 0x01, 0xAF,
+ 0x01, 0xFA, 0x08, 0x00, 0x01, 0xDF, 0x01, 0xF5, 0x06, 0x00, 0x01, 0x09,
+ 0x01, 0xFF, 0x01, 0xC0, 0x07, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xB0,
+ 0x06, 0x00, 0x01, 0x8F, 0x01, 0xFD, 0x01, 0x10, 0x07, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x20, 0x05, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xC1,
+ 0x08, 0x00, 0x01, 0xBF, 0x01, 0xF8, 0x06, 0x00, 0x01, 0xAF, 0x01, 0xFB,
+ 0x08, 0x00, 0x01, 0x05, 0x01, 0xFF, 0x01, 0xE0, 0x05, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xA0, 0x08, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50,
+ 0x04, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x01, 0xF9, 0x09, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x05, 0x00, 0x01, 0x09, 0x01, 0xFF, 0x01, 0xFE, 0x03, 0xEE,
+ 0x01, 0xE6, 0x04, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF2, 0x05, 0x00,
+ 0x01, 0x0A, 0x05, 0xFF, 0x01, 0xF7, 0x04, 0x00, 0x01, 0x0A, 0x01, 0xEE,
+ 0x01, 0x70, 0x05, 0x00, 0x01, 0x04, 0x05, 0x66, 0x01, 0x62, 0xBE, 0x00,
+
+ /* 37 FRACTION_THREE_FOURTHS */
+ 0x87, 0x00, 0x01, 0x02, 0x01, 0x34, 0x01, 0x42, 0x08, 0x00, 0x01, 0x01,
+ 0x01, 0x55, 0x01, 0x50, 0x04, 0x00, 0x01, 0x4C, 0x03, 0xFF, 0x01, 0xE9,
+ 0x01, 0x10, 0x06, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0x80, 0x04, 0x00,
+ 0x01, 0x7F, 0x01, 0xFF, 0x01, 0xFE, 0x02, 0xFF, 0x01, 0xE2, 0x06, 0x00,
+ 0x01, 0x4F, 0x01, 0xFE, 0x05, 0x00, 0x01, 0x47, 0x01, 0x30, 0x01, 0x00,
+ 0x01, 0x05, 0x01, 0xEF, 0x01, 0xFB, 0x06, 0x00, 0x01, 0xDF, 0x01, 0xF5,
+ 0x09, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x05, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xB0, 0x09, 0x00, 0x01, 0x1F, 0x01, 0xFF, 0x05, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x20, 0x09, 0x00, 0x01, 0x6F, 0x01, 0xFB, 0x05, 0x00,
+ 0x01, 0xBF, 0x01, 0xF8, 0x07, 0x00, 0x01, 0x03, 0x01, 0x44, 0x01, 0x5A,
+ 0x01, 0xFF, 0x01, 0xD1, 0x04, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE0,
+ 0x07, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x01, 0xE7, 0x05, 0x00, 0x01, 0x0D,
+ 0x01, 0xFF, 0x01, 0x50, 0x07, 0x00, 0x01, 0x0B, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x70, 0x04, 0x00, 0x01, 0x7F, 0x01, 0xFB, 0x0A, 0x00,
+ 0x01, 0x16, 0x01, 0xDF, 0x01, 0xF9, 0x03, 0x00, 0x01, 0x02, 0x01, 0xFF,
+ 0x01, 0xF2, 0x0B, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0x20, 0x02, 0x00,
+ 0x01, 0x0B, 0x01, 0xFF, 0x01, 0x80, 0x0B, 0x00, 0x01, 0x0A, 0x01, 0xFF,
+ 0x01, 0x60, 0x02, 0x00, 0x01, 0x4F, 0x01, 0xFE, 0x0C, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0x60, 0x02, 0x00, 0x01, 0xDF, 0x01, 0xF5, 0x0C, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x30, 0x01, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xB0, 0x04, 0x00, 0x01, 0x47, 0x01, 0x77, 0x02, 0x00, 0x01, 0xD7,
+ 0x01, 0x42, 0x01, 0x01, 0x01, 0x38, 0x01, 0xEF, 0x01, 0xFC, 0x02, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x02, 0x02, 0xFF,
+ 0x02, 0x00, 0x05, 0xFF, 0x01, 0xC1, 0x02, 0x00, 0x01, 0xBF, 0x01, 0xF8,
+ 0x04, 0x00, 0x01, 0x0C, 0x02, 0xFF, 0x02, 0x00, 0x01, 0x7B, 0x01, 0xEF,
+ 0x02, 0xFF, 0x01, 0xB6, 0x02, 0x00, 0x01, 0x04, 0x01, 0xFF, 0x01, 0xE0,
+ 0x04, 0x00, 0x01, 0x9F, 0x01, 0xBE, 0x01, 0xFF, 0x04, 0x00, 0x01, 0x22,
+ 0x01, 0x10, 0x03, 0x00, 0x01, 0x0D, 0x01, 0xFF, 0x01, 0x50, 0x03, 0x00,
+ 0x01, 0x04, 0x01, 0xFE, 0x01, 0x1E, 0x01, 0xFF, 0x09, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x04, 0x00, 0x01, 0x1E, 0x01, 0xF3, 0x01, 0x0E, 0x01, 0xFF,
+ 0x08, 0x00, 0x01, 0x02, 0x01, 0xFF, 0x01, 0xF2, 0x04, 0x00, 0x01, 0xCF,
+ 0x01, 0x70, 0x01, 0x0E, 0x01, 0xFF, 0x08, 0x00, 0x01, 0x0B, 0x01, 0xFF,
+ 0x01, 0x80, 0x03, 0x00, 0x01, 0x08, 0x01, 0xFB, 0x01, 0x00, 0x01, 0x0E,
+ 0x01, 0xFF, 0x08, 0x00, 0x01, 0x5F, 0x01, 0xFE, 0x04, 0x00, 0x01, 0x4F,
+ 0x01, 0xE1, 0x01, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x08, 0x00, 0x01, 0xDF,
+ 0x01, 0xF4, 0x03, 0x00, 0x01, 0x01, 0x01, 0xEF, 0x01, 0x40, 0x01, 0x00,
+ 0x01, 0x0E, 0x01, 0xFF, 0x07, 0x00, 0x01, 0x08, 0x01, 0xFF, 0x01, 0xB0,
+ 0x03, 0x00, 0x01, 0x0B, 0x01, 0xF8, 0x02, 0x00, 0x01, 0x0E, 0x01, 0xFF,
+ 0x07, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x20, 0x03, 0x00, 0x01, 0x3F,
+ 0x01, 0xF9, 0x02, 0x99, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x99, 0x06, 0x00,
+ 0x01, 0xBF, 0x01, 0xF8, 0x04, 0x00, 0x01, 0x4F, 0x06, 0xFF, 0x05, 0x00,
+ 0x01, 0x05, 0x01, 0xFF, 0x01, 0xD0, 0x04, 0x00, 0x01, 0x29, 0x03, 0x99,
+ 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x99, 0x05, 0x00, 0x01, 0x0D, 0x01, 0xFF,
+ 0x01, 0x40, 0x08, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x06, 0x00, 0x01, 0x8F,
+ 0x01, 0xFB, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x05, 0x00, 0x01, 0x02,
+ 0x01, 0xFF, 0x01, 0xF2, 0x09, 0x00, 0x01, 0x0E, 0x01, 0xFF, 0x05, 0x00,
+ 0x01, 0x0A, 0x01, 0xEE, 0x01, 0x70, 0x09, 0x00, 0x01, 0x04, 0x01, 0x55,
+ 0xBF, 0x00,
+#endif // TOUCH_UI_UTF8_FRACTIONS
+
+#if ENABLED(TOUCH_UI_UTF8_SYMBOLS)
+ /* 38 MICRON_SIGN */
+ 0xFF, 0x00, 0x1F, 0x00, 0x01, 0x02, 0x01, 0x44, 0x01, 0x40, 0x05, 0x00,
+ 0x01, 0x14, 0x01, 0x44, 0x01, 0x10, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00,
+ 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x05, 0x00, 0x01, 0x4F, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF4, 0x05, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF6, 0x05, 0x00, 0x01, 0x9F, 0x01, 0xFF, 0x01, 0x70, 0x08, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xFA, 0x05, 0x00, 0x01, 0xEF, 0x01, 0xFF,
+ 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x02, 0xFF, 0x01, 0x20, 0x03, 0x00,
+ 0x01, 0x07, 0x02, 0xFF, 0x01, 0x70, 0x08, 0x00, 0x01, 0x07, 0x02, 0xFF,
+ 0x01, 0xD2, 0x03, 0x00, 0x01, 0x6F, 0x02, 0xFF, 0x01, 0xA0, 0x08, 0x00,
+ 0x01, 0x07, 0x03, 0xFF, 0x01, 0xA6, 0x01, 0x55, 0x01, 0x8D, 0x03, 0xFF,
+ 0x01, 0xF9, 0x01, 0xA4, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF7,
+ 0x05, 0xFF, 0x01, 0x5D, 0x02, 0xFF, 0x01, 0xF4, 0x07, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xF3, 0x01, 0x5F, 0x03, 0xFF, 0x01, 0xF5, 0x01, 0x06,
+ 0x02, 0xFF, 0x01, 0xF4, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3,
+ 0x01, 0x01, 0x01, 0x7C, 0x01, 0xDD, 0x01, 0xC7, 0x01, 0x10, 0x01, 0x00,
+ 0x01, 0x6C, 0x01, 0xDB, 0x01, 0x50, 0x07, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x10, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x10, 0x00,
+ 0x01, 0x07, 0x01, 0xFF, 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xFF,
+ 0x01, 0xF3, 0x10, 0x00, 0x01, 0x07, 0x01, 0xEE, 0x01, 0xE3, 0x35, 0x00,
+
+ /* 39 PILCROW_SIGN */
+ 0x9C, 0x00, 0x01, 0x16, 0x01, 0x9B, 0x04, 0xCC, 0x01, 0xCA, 0x0B, 0x00,
+ 0x01, 0x19, 0x06, 0xFF, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0x03, 0x01, 0xEF,
+ 0x03, 0xFF, 0x01, 0xFB, 0x01, 0xAA, 0x01, 0xAF, 0x01, 0xFD, 0x0A, 0x00,
+ 0x01, 0x2E, 0x04, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD,
+ 0x0A, 0x00, 0x01, 0xBF, 0x04, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F,
+ 0x01, 0xFD, 0x09, 0x00, 0x01, 0x03, 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x09, 0x00, 0x01, 0x08, 0x05, 0xFF, 0x01, 0xF2,
+ 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x09, 0x00, 0x01, 0x0B, 0x05, 0xFF,
+ 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x09, 0x00, 0x01, 0x0C,
+ 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x09, 0x00,
+ 0x01, 0x0B, 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD,
+ 0x09, 0x00, 0x01, 0x0A, 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F,
+ 0x01, 0xFD, 0x09, 0x00, 0x01, 0x06, 0x05, 0xFF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0xEF, 0x04, 0xFF, 0x01, 0xF2,
+ 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0x6F, 0x04, 0xFF,
+ 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x0A, 0x00, 0x01, 0x08,
+ 0x04, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD, 0x0B, 0x00,
+ 0x01, 0x5E, 0x03, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F, 0x01, 0xFD,
+ 0x0C, 0x00, 0x01, 0x6B, 0x02, 0xFF, 0x01, 0xF2, 0x01, 0x00, 0x01, 0x0F,
+ 0x01, 0xFD, 0x0D, 0x00, 0x01, 0x01, 0x01, 0xCF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0xBF, 0x01, 0xF2, 0x01, 0x00,
+ 0x01, 0x0F, 0x01, 0xFD, 0x0E, 0x00, 0x01, 0x34, 0x01, 0x40, 0x01, 0x00,
+ 0x01, 0x04, 0x01, 0x43, 0x7A, 0x00,
+
+ /* 40 BROKEN_BAR */
+ 0xAD, 0x00, 0x01, 0x07, 0x01, 0x99, 0x01, 0x60, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x08, 0x01, 0xBB, 0x01, 0x70, 0x6F, 0x00, 0x01, 0x0B,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0,
+ 0x10, 0x00, 0x01, 0x0C, 0x01, 0xFF, 0x01, 0xA0, 0x10, 0x00, 0x01, 0x04,
+ 0x01, 0x55, 0x01, 0x30, 0x47, 0x00,
+
+ /* 41 SECTION_SIGN */
+ 0x89, 0x00, 0x01, 0x35, 0x01, 0x64, 0x01, 0x31, 0x0E, 0x00, 0x01, 0x01,
+ 0x01, 0x9E, 0x03, 0xFF, 0x01, 0xD9, 0x01, 0x30, 0x0C, 0x00, 0x01, 0x2E,
+ 0x05, 0xFF, 0x01, 0xB0, 0x0C, 0x00, 0x01, 0xEF, 0x01, 0xFF, 0x01, 0xFB,
+ 0x01, 0x98, 0x01, 0xAE, 0x01, 0xFF, 0x01, 0xB0, 0x0B, 0x00, 0x01, 0x07,
+ 0x01, 0xFF, 0x01, 0xFC, 0x01, 0x10, 0x02, 0x00, 0x01, 0x39, 0x01, 0xA0,
+ 0x0B, 0x00, 0x01, 0x0B, 0x01, 0xFF, 0x01, 0xF2, 0x10, 0x00, 0x01, 0x0C,
+ 0x01, 0xFF, 0x01, 0xF0, 0x10, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xF3,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x20, 0x10, 0x00,
+ 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xE4, 0x10, 0x00, 0x01, 0x1D, 0x02, 0xFF,
+ 0x01, 0xA1, 0x0F, 0x00, 0x01, 0x4E, 0x03, 0xFF, 0x01, 0x70, 0x0D, 0x00,
+ 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF9, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFD,
+ 0x01, 0x30, 0x0C, 0x00, 0x01, 0x3F, 0x01, 0xFF, 0x01, 0x60, 0x01, 0x07,
+ 0x02, 0xFF, 0x01, 0xF8, 0x0C, 0x00, 0x01, 0xBF, 0x01, 0xF9, 0x02, 0x00,
+ 0x01, 0x19, 0x02, 0xFF, 0x01, 0xC0, 0x0B, 0x00, 0x01, 0xFF, 0x01, 0xF3,
+ 0x03, 0x00, 0x01, 0x4E, 0x01, 0xFF, 0x01, 0xFB, 0x0A, 0x00, 0x01, 0x01,
+ 0x01, 0xFF, 0x01, 0xF2, 0x03, 0x00, 0x01, 0x01, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0x40, 0x09, 0x00, 0x01, 0x01, 0x01, 0xFF, 0x01, 0xF7, 0x04, 0x00,
+ 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x90, 0x0A, 0x00, 0x01, 0xDF, 0x01, 0xFF,
+ 0x01, 0x20, 0x03, 0x00, 0x01, 0x0A, 0x01, 0xFF, 0x01, 0xB0, 0x0A, 0x00,
+ 0x01, 0x6F, 0x01, 0xFF, 0x01, 0xF5, 0x03, 0x00, 0x01, 0x08, 0x01, 0xFF,
+ 0x01, 0xA0, 0x0A, 0x00, 0x01, 0x0A, 0x02, 0xFF, 0x01, 0x91, 0x02, 0x00,
+ 0x01, 0x0C, 0x01, 0xFF, 0x01, 0x70, 0x0B, 0x00, 0x01, 0x8F, 0x01, 0xFF,
+ 0x01, 0xFE, 0x01, 0x60, 0x01, 0x00, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x10,
+ 0x0B, 0x00, 0x01, 0x03, 0x01, 0xDF, 0x01, 0xFF, 0x01, 0xFD, 0x01, 0x46,
+ 0x01, 0xFF, 0x01, 0xF5, 0x0D, 0x00, 0x01, 0x07, 0x04, 0xFF, 0x01, 0x50,
+ 0x0E, 0x00, 0x01, 0x2A, 0x02, 0xFF, 0x01, 0xF5, 0x10, 0x00, 0x01, 0x4E,
+ 0x01, 0xFF, 0x01, 0xFE, 0x01, 0x20, 0x0F, 0x00, 0x01, 0x01, 0x01, 0xCF,
+ 0x01, 0xFF, 0x01, 0xC0, 0x10, 0x00, 0x01, 0x1E, 0x01, 0xFF, 0x01, 0xF3,
+ 0x10, 0x00, 0x01, 0x06, 0x01, 0xFF, 0x01, 0xF6, 0x10, 0x00, 0x01, 0x05,
+ 0x01, 0xFF, 0x01, 0xF6, 0x0B, 0x00, 0x01, 0x01, 0x04, 0x00, 0x01, 0x0A,
+ 0x01, 0xFF, 0x01, 0xF3, 0x0B, 0x00, 0x01, 0x08, 0x01, 0xE8, 0x01, 0x20,
+ 0x01, 0x00, 0x01, 0x01, 0x01, 0x8F, 0x01, 0xFF, 0x01, 0xE0, 0x0B, 0x00,
+ 0x01, 0x08, 0x01, 0xFF, 0x01, 0xFE, 0x01, 0xCB, 0x01, 0xDF, 0x02, 0xFF,
+ 0x01, 0x40, 0x0B, 0x00, 0x01, 0x08, 0x05, 0xFF, 0x01, 0xF5, 0x0D, 0x00,
+ 0x01, 0x49, 0x01, 0xDF, 0x02, 0xFF, 0x01, 0xE8, 0x01, 0x20, 0x0F, 0x00,
+ 0x01, 0x12, 0x01, 0x21, 0x7F, 0x00,
+
+ /* 42 NOT_SIGN */
+ 0xFF, 0x00, 0x7F, 0x00, 0x01, 0x12, 0x0C, 0x22, 0x06, 0x00, 0x01, 0x9F,
+ 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40,
+ 0x05, 0x00, 0x01, 0x9F, 0x0C, 0xFF, 0x01, 0x40, 0x05, 0x00, 0x01, 0x24,
+ 0x0A, 0x44, 0x01, 0x6F, 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x40,
+ 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x40,
+ 0x10, 0x00, 0x01, 0x2F, 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x2F,
+ 0x01, 0xFF, 0x01, 0x40, 0x10, 0x00, 0x01, 0x17, 0x01, 0x77, 0x01, 0x10,
+ 0xFF, 0x00, 0x34, 0x00
+#endif // TOUCH_UI_UTF8_SYMBOLS
+};
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/ftdi_eve_lib.h b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/ftdi_eve_lib.h
new file mode 100644
index 0000000..c5ddbb4
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/ftdi_eve_lib.h
@@ -0,0 +1,27 @@
+/******************
+ * ftdi_eve_lib.h *
+ ******************/
+
+/****************************************************************************
+ * Written By Mark Pelletier 2019 - Aleph Objects, Inc. *
+ * Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
+ * *
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+#pragma once
+
+#include "compat.h"
+#include "basic/ftdi_basic.h"
+#include "extended/ftdi_extended.h"
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/file2cpp.py b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/file2cpp.py
new file mode 100644
index 0000000..6aa8947
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/file2cpp.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+
+# Written By Marcio Teixeira 2021 - SynDaver Labs, Inc.
+#
+# 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.
+#
+# To view a copy of the GNU General Public License, go to the following
+# location: .
+
+from __future__ import print_function
+import argparse
+import textwrap
+import os
+import zlib
+
+def deflate(data):
+ return zlib.compress(data)
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Converts a file into a packed C array for use as data')
+ parser.add_argument("input")
+ parser.add_argument("-d", "--deflate", action="store_true", help="Packs the data using the deflate algorithm")
+ args = parser.parse_args()
+
+ varname = os.path.splitext(os.path.basename(args.input))[0];
+
+ with open(args.input, "rb") as in_file:
+ data = in_file.read()
+ if args.deflate:
+ data = deflate(data)
+ data = bytearray(data)
+ data = list(map(lambda a: "0x" + format(a, '02x'), data))
+ nElements = len(data)
+ data = ', '.join(data)
+ data = textwrap.fill(data, 75, initial_indent = ' ', subsequent_indent = ' ')
+
+ print("const unsigned char " + varname + "[" + format(nElements) + "] PROGMEM = {")
+ print(data)
+ print("};")
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/font2cpp.py b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/font2cpp.py
new file mode 100644
index 0000000..0c4499e
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/font2cpp.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+
+# Written By Marcio Teixeira 2019 - Aleph Objects, Inc.
+#
+# 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.
+#
+# To view a copy of the GNU General Public License, go to the following
+# location: .
+
+from __future__ import print_function
+from PIL import Image
+import argparse
+import textwrap
+
+def pack_rle(data):
+ """Use run-length encoding to pack the bytes"""
+ rle = []
+ value = data[0]
+ count = 0
+ for i in data:
+ if i != value or count == 255:
+ rle.append(count)
+ rle.append(value)
+ value = i
+ count = 1
+ else:
+ count += 1
+ rle.append(count)
+ rle.append(value)
+ return rle
+
+class WriteSource:
+ def __init__(self, lines_in_blocks):
+ self.blocks = []
+ self.values = []
+ self.block_size = lines_in_blocks
+ self.rows = 0
+
+ def add_pixel(self, value):
+ self.values.append(value)
+
+ def convert_to_4bpp(self, data, chunk_size = 0):
+ # Invert the image
+ data = list(map(lambda i: 255 - i, data))
+ # Quanitize 8-bit values into 4-bits
+ data = list(map(lambda i: i >> 4, data))
+ # Make sure there is an even number of elements
+ if (len(data) & 1) == 1:
+ data.append(0)
+ # Combine each two adjacent values into one
+ i = iter(data)
+ data = list(map(lambda a, b: a << 4 | b, i ,i))
+ # Pack the data
+ data = pack_rle(data)
+ # Convert values into hex strings
+ return list(map(lambda a: "0x" + format(a, '02x'), data))
+
+ def end_row(self, y):
+ # Pad each row into even number of values
+ if len(self.values) & 1:
+ self.values.append(0)
+
+ self.rows += 1
+ if self.block_size and (self.rows % self.block_size) == 0:
+ self.blocks.append(self.values)
+ self.values = []
+
+ def write(self):
+ if len(self.values):
+ self.blocks.append(self.values)
+
+ block_strs = [];
+ for b in self.blocks:
+ data = self.convert_to_4bpp(b)
+ data = ', '.join(data)
+ data = textwrap.fill(data, 75, initial_indent = ' ', subsequent_indent = ' ')
+ block_strs.append(data)
+
+ print("const unsigned char font[] PROGMEM = {")
+ for i, b in enumerate(block_strs):
+ if i:
+ print(',')
+ print('\n /* {} */'.format(i))
+ print(b, end='')
+ print("\n};")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Converts a grayscale bitmap into a 16-level RLE packed C array for use as font data')
+ parser.add_argument("input")
+ parser.add_argument('--char_height', help='Adds a separator every so many lines', type=int)
+ args = parser.parse_args()
+
+ writer = WriteSource(args.char_height)
+
+ img = Image.open(args.input).convert('L')
+ for y in range(img.height):
+ for x in range(img.width):
+ writer.add_pixel(img.getpixel((x,y)))
+ writer.end_row(y)
+ writer.write()
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/img2cpp.py b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/img2cpp.py
new file mode 100644
index 0000000..74be574
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/img2cpp.py
@@ -0,0 +1,113 @@
+#!/usr/bin/python
+
+# Written By Marcio Teixeira 2021 - SynDaver Labs, Inc.
+#
+# 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.
+#
+# To view a copy of the GNU General Public License, go to the following
+# location: .
+
+from __future__ import print_function
+from PIL import Image
+import argparse
+import textwrap
+import os
+import sys
+import zlib
+
+class WriteSource:
+ def __init__(self, mode):
+ self.values = []
+ self.mode = mode
+ self.offset = 8
+ self.byte = 0
+
+ def finish_byte(self):
+ if self.offset != 8:
+ self.values.append(self.byte)
+ self.offset = 8
+ self.byte = 0
+
+ def add_bits_to_byte(self, value, size = 1):
+ self.offset -= size
+ self.byte = self.byte | value << self.offset
+ if self.offset == 0:
+ self.finish_byte()
+
+ def append_rgb565(self, color):
+ value = ((color[0] & 0xF8) << 8) + ((color[1] & 0xFC) << 3) + ((color[2] & 0xF8) >> 3)
+ self.values.append((value & 0x00FF) >> 0);
+ self.values.append((value & 0xFF00) >> 8);
+
+ def append_rgb332(self, color):
+ value = (color[0] & 0xE0) + ((color[1] & 0xE0) >> 3) + ((color[2] & 0xC0) >> 6)
+ self.values.append(value);
+
+ def append_grayscale(self, color, bits):
+ luminance = int(0.2126 * color[0] + 0.7152 * color[1] + 0.0722 * color[2])
+ self.add_bits_to_byte(luminance >> (8 - bits), bits)
+
+ def deflate(self, data):
+ return zlib.compress(data)
+
+ def add_pixel(self, color):
+ if self.mode == "l1":
+ self.append_grayscale(color, 1)
+ elif self.mode == "l2":
+ self.append_grayscale(color, 2)
+ elif self.mode == "l4":
+ self.append_grayscale(color, 4)
+ elif self.mode == "l8":
+ self.append_grayscale(color, 8)
+ elif self.mode == "rgb565":
+ self.append_rgb565(color)
+ elif self.mode == "rgb332":
+ self.append_rgb332(color)
+
+ def end_row(self, y):
+ if self.mode in ["l1", "l2", "l3"]:
+ self.finish_byte()
+
+ def write(self, varname, deflate):
+ print("Length of uncompressed data: ", len(self.values), file=sys.stderr)
+ data = bytes(bytearray(self.values))
+ if deflate:
+ data = self.deflate(data)
+ print("Length of data after compression: ", len(data), file=sys.stderr)
+ data = bytearray(data)
+ data = list(map(lambda a: "0x" + format(a, '02x'), data))
+ nElements = len(data)
+ data = ', '.join(data)
+ data = textwrap.fill(data, 75, initial_indent = ' ', subsequent_indent = ' ')
+
+ print("const unsigned char " + varname + "[" + format(nElements) + "] PROGMEM = {")
+ print(data)
+ print("};")
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description='Converts a bitmap into a C array')
+ parser.add_argument("input")
+ parser.add_argument("-d", "--deflate", action="store_true", help="Packs the data using the deflate algorithm")
+ parser.add_argument("-m", "--mode", default="l1", help="Mode, can be l1, l2, l4, l8, rgb332 or rgb565")
+ args = parser.parse_args()
+
+ varname = os.path.splitext(os.path.basename(args.input))[0];
+
+ writer = WriteSource(args.mode)
+
+ img = Image.open(args.input)
+ print("Image height: ", img.height, file=sys.stderr)
+ print("Image width: ", img.width, file=sys.stderr)
+ for y in range(img.height):
+ for x in range(img.width):
+ writer.add_pixel(img.getpixel((x,y)))
+ writer.end_row(y)
+ writer.write(varname, args.deflate)
diff --git a/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/svg2cpp.py b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/svg2cpp.py
new file mode 100644
index 0000000..f6e4a3e
--- /dev/null
+++ b/src/lcd/extui/ftdi_eve_touch_ui/ftdi_eve_lib/scripts/svg2cpp.py
@@ -0,0 +1,280 @@
+#!/usr/bin/python
+
+# Written By Marcio Teixeira 2018 - Aleph Objects, Inc.
+#
+# 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.
+#
+# To view a copy of the GNU General Public License, go to the following
+# location: .
+
+from __future__ import print_function
+import argparse,re,sys
+
+usage = '''
+This program extracts line segments from a SVG file and writes
+them as coordinates in a C array. The x and y values will be
+scaled from 0x0000 to 0xFFFE. 0xFFFF is used as path separator.
+
+This program can only interpret straight segments, not curves.
+It also cannot handle SVG transform attributes. To convert an
+SVG file into the proper format, use the following procedure:
+
+ - Load SVG file into Inkscape
+ - Convert all Objects to Paths (Path -> Object to Path)
+ - Convert all Strokes to Paths (Path -> Stroke to Path)
+ - Combine all paths into one (Path -> Combine) [1]
+ - Convert all curves into short line segments
+ (Extensions -> Modify Paths -> Flatten Beziers...)
+ - Save as new SVG
+ - Convert into a header file using this utility
+ - To give paths individual names, break apart paths and
+ use the XML Editor to set the "id" attributes.
+
+[1] Combining paths is necessary to remove transforms. You
+could also use inkscape-applytransforms Inkscape extension.
+
+'''
+
+header = '''
+/****************************************************************************
+ * 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. *
+ * *
+ * To view a copy of the GNU General Public License, go to the following *
+ * location: . *
+ ****************************************************************************/
+
+/**
+ * This file was auto-generated using "svg2cpp.py"
+ *
+ * The encoding consists of x,y pairs with the min and max scaled to
+ * 0x0000 and 0xFFFE. A single 0xFFFF in the data stream indicates the
+ * start of a new closed path.
+ */
+
+#pragma once
+'''
+
+class ComputeBoundingBox:
+ def reset(self):
+ self.x_min = float(" inf")
+ self.y_min = float(" inf")
+ self.x_max = float("-inf")
+ self.y_max = float("-inf")
+ self.n_points = 0
+ self.n_paths = 0
+
+ def command(self, type, x, y):
+ self.x_min = min(self.x_min, x)
+ self.x_max = max(self.x_max, x)
+ self.y_min = min(self.y_min, y)
+ self.y_max = max(self.y_max, y)
+
+ if type == "M":
+ self.n_paths += 1
+ self.n_points += 1
+
+ def scale(self, x, y):
+ x -= self.x_min
+ y -= self.y_min
+ x /= self.x_max - self.x_min
+ y /= self.y_max - self.y_min
+ #y = 1 - y # Flip upside down
+ return (x, y)
+
+ def path_finished(self, id):
+ pass
+
+ def write(self):
+ print("constexpr float x_min = %f;" % self.x_min)
+ print("constexpr float x_max = %f;" % self.x_max)
+ print("constexpr float y_min = %f;" % self.y_min)
+ print("constexpr float y_max = %f;" % self.y_max)
+ print()
+
+ def from_svg_view_box(self, svg):
+ s = re.search('