diff options
author | Georgiy Bondarenko <69736697+nehilo@users.noreply.github.com> | 2021-03-04 20:54:23 +0300 |
---|---|---|
committer | Georgiy Bondarenko <69736697+nehilo@users.noreply.github.com> | 2021-03-04 20:54:23 +0300 |
commit | e8701195e66f2d27ffe17fb514eae8173795aaf7 (patch) | |
tree | 9f519c4abf6556b9ae7190a6210d87ead1dfadde /Marlin/src/lcd/extui | |
download | kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.tar.xz kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.zip |
Initial commit
Diffstat (limited to 'Marlin/src/lcd/extui')
319 files changed, 61817 insertions, 0 deletions
diff --git a/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp b/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp new file mode 100644 index 0000000..06baa4c --- /dev/null +++ b/Marlin/src/lcd/extui/anycubic_chiron_lcd.cpp @@ -0,0 +1,130 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/** + * lcd/extui/anycubic_chiron_lcd.cpp + * + * Anycubic Chiron TFT support for Marlin + */ + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(ANYCUBIC_LCD_CHIRON) + +#include "ui_api.h" +#include "lib/anycubic_chiron/chiron_tft.h" + +using namespace Anycubic; + +namespace ExtUI { + + void onStartup() { Chiron.Startup(); } + + void onIdle() { Chiron.IdleLoop(); } + + void onPrinterKilled(PGM_P const error, PGM_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 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 onHomingComplete() {} + void onPrintFinished() {} + + 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) <= ExtUI::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) <= ExtUI::eeprom_data_size); + // memcpy(&myDataStruct, buff, sizeof(myDataStruct)); + } + + void onConfigurationStoreWritten(bool success) { + // Called after the entire EEPROM has been written, + // whether successful or not. + } + + void onConfigurationStoreRead(bool success) { + // Called after the entire EEPROM has been read, + // whether successful or not. + } + + #if HAS_MESH + void onMeshLevelingStart() {} + + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) { + // Called when any mesh points are updated + //SERIAL_ECHOLNPAIR("onMeshUpdate() x:", xpos, " y:", ypos, " z:", zval); + } + + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) { + // Called to indicate a special condition + //SERIAL_ECHOLNPAIR("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/Marlin/src/lcd/extui/anycubic_i3mega_lcd.cpp b/Marlin/src/lcd/extui/anycubic_i3mega_lcd.cpp new file mode 100644 index 0000000..e2bd960 --- /dev/null +++ b/Marlin/src/lcd/extui/anycubic_i3mega_lcd.cpp @@ -0,0 +1,117 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/** + * anycubic_i3mega_lcd.cpp + */ + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(ANYCUBIC_LCD_I3MEGA) + +#include "lib/anycubic_i3mega/anycubic_i3mega_lcd.h" +#include "ui_api.h" + +#include <Arduino.h> // for the ::tone() call + +namespace ExtUI { + + void onStartup() { AnycubicTFT.OnSetup(); } + void onIdle() { AnycubicTFT.OnCommandScan(); } + void onPrinterKilled(PGM_P const error, PGM_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) { + #if ENABLED(SPEAKER) + ::tone(BEEPER_PIN, frequency, duration); + #endif + } + 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 onHomingComplete() {} + void onPrintFinished() {} + + 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) <= ExtUI::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) <= ExtUI::eeprom_data_size); + // memcpy(&myDataStruct, buff, sizeof(myDataStruct)); + } + + void onConfigurationStoreWritten(bool success) { + // Called after the entire EEPROM has been written, + // whether successful or not. + } + + void onConfigurationStoreRead(bool success) { + // Called after the entire EEPROM has been read, + // whether successful or not. + } + + #if HAS_MESH + + void onMeshLevelingStart() {} + + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) { + // 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/Marlin/src/lcd/extui/dgus_lcd.cpp b/Marlin/src/lcd/extui/dgus_lcd.cpp new file mode 100644 index 0000000..9fcb6c8 --- /dev/null +++ b/Marlin/src/lcd/extui/dgus_lcd.cpp @@ -0,0 +1,158 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/** + * dgus_lcd.cpp + * + * DGUS implementation for Marlin by coldtobi, Feb-May 2019 + */ + +#include "../../inc/MarlinConfigPre.h" + +#if HAS_DGUS_LCD + +#include "ui_api.h" +#include "lib/dgus/DGUSDisplay.h" +#include "lib/dgus/DGUSDisplayDef.h" +#include "lib/dgus/DGUSScreenHandler.h" + +namespace ExtUI { + + void onStartup() { + dgusdisplay.InitDisplay(); + ScreenHandler.UpdateScreenVPData(); + } + + void onIdle() { ScreenHandler.loop(); } + + void onPrinterKilled(PGM_P const error, PGM_P const component) { + ScreenHandler.sendinfoscreen(GET_TEXT(MSG_HALTED), error, NUL_STR, GET_TEXT(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(PSTR("Please confirm."), nullptr, msg, nullptr, true, true, false, true); + ScreenHandler.SetupConfirmAction(ExtUI::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 onHomingComplete() {} + void onPrintFinished() {} + + 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) <= ExtUI::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) <= ExtUI::eeprom_data_size); + // memcpy(&myDataStruct, buff, sizeof(myDataStruct)); + } + + void onConfigurationStoreWritten(bool success) { + // Called after the entire EEPROM has been written, + // whether successful or not. + } + + void onConfigurationStoreRead(bool success) { + // Called after the entire EEPROM has been read, + // whether successful or not. + } + + #if HAS_MESH + void onMeshLevelingStart() {} + + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) { + // Called when any mesh points are updated + } + + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) { + // Called to indicate a special condition + } + #endif + + #if ENABLED(POWER_LOSS_RECOVERY) + void onPowerLossResume() { + // Called on resume from power-loss + 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_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 diff --git a/Marlin/src/lcd/extui/example.cpp b/Marlin/src/lcd/extui/example.cpp new file mode 100644 index 0000000..dd4b331 --- /dev/null +++ b/Marlin/src/lcd/extui/example.cpp @@ -0,0 +1,125 @@ +/********************* + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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(PGM_P const error, PGM_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 onHomingComplete() {} + void onPrintFinished() {} + + 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) <= ExtUI::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) <= ExtUI::eeprom_data_size); + // memcpy(&myDataStruct, buff, sizeof(myDataStruct)); + } + + void onConfigurationStoreWritten(bool success) { + // Called after the entire EEPROM has been written, + // whether successful or not. + } + + void onConfigurationStoreRead(bool success) { + // Called after the entire EEPROM has been read, + // whether successful or not. + } + + #if HAS_MESH + void onMeshLevelingStart() {} + + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) { + // Called when any mesh points are updated + } + + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::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 + } + #endif + + void onSteppersDisabled() {} + void onSteppersEnabled() {} +} + +#endif // EXTUI_EXAMPLE && EXTENSIBLE_UI diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp new file mode 100644 index 0000000..19f8ec8 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.cpp @@ -0,0 +1,164 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/** + * lcd/extui/lib/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. * + ***************************************************************************/ + +#include "../../../../inc/MarlinConfigPre.h" + +#if ENABLED(ANYCUBIC_LCD_CHIRON) + +#include "FileNavigator.h" +#include "chiron_tft.h" + +using namespace ExtUI; + +namespace Anycubic { + + FileNavigator filenavigator; + + FileList FileNavigator::filelist; // Instance of the Marlin file API + char FileNavigator::currentfoldername[MAX_PATH_LEN]; // Current folder path + uint16_t FileNavigator::lastindex; + uint8_t FileNavigator::folderdepth; + uint16_t FileNavigator::currentindex; // override the panel request + + FileNavigator::FileNavigator() { reset(); } + + void FileNavigator::reset() { + currentfoldername[0] = '\0'; + folderdepth = 0; + currentindex = 0; + lastindex = 0; + // Start at root folder + while (!filelist.isAtRootDir()) filelist.upDir(); + refresh(); + } + + void FileNavigator::refresh() { filelist.refresh(); } + + void FileNavigator::getFiles(uint16_t index) { + uint8_t files = 4; + if (index == 0) currentindex = 0; + + // Each time we change folder we reset the file index to 0 and keep track + // of the current position as the TFT panel isnt aware of folders trees. + if (index > 0) { + --currentindex; // go back a file to take account off the .. we added to the root. + if (index > lastindex) + currentindex += files; + else + currentindex = currentindex < 4 ? 0 : currentindex - files; + } + lastindex = index; + + #if ACDEBUG(AC_FILE) + SERIAL_ECHOLNPAIR("index=", index, " currentindex=", currentindex); + #endif + + if (currentindex == 0 && folderdepth > 0) { // Add a link to go up a folder + TFTSer.println("<<"); + TFTSer.println(".."); + files--; + } + + for (uint16_t seek = currentindex; seek < currentindex + files; seek++) { + if (filelist.seek(seek)) { + sendFile(); + #if ACDEBUG(AC_FILE) + SERIAL_ECHOLNPAIR("-", seek, " '", filelist.longFilename(), "' '", currentfoldername, "", filelist.shortFilename(), "'\n"); + #endif + } + } + } + + void FileNavigator::sendFile() { + // send the file and folder info to the panel + // this info will be returned when the file is selected + // Permitted special characters in file name -_*#~ + // Panel can display 22 characters per line + if (filelist.isDir()) { + //TFTSer.print(currentfoldername); + TFTSer.println(filelist.shortFilename()); + TFTSer.print(filelist.shortFilename()); + TFTSer.println("/"); + } + else { + // Logical Name + TFTSer.print("/"); + if (folderdepth > 0) TFTSer.print(currentfoldername); + + TFTSer.println(filelist.shortFilename()); + + // Display Name + TFTSer.println(filelist.longFilename()); + } + } + void FileNavigator::changeDIR(char *folder) { + #if ACDEBUG(AC_FILE) + SERIAL_ECHOLNPAIR("currentfolder: ", currentfoldername, " New: ", folder); + #endif + if (folderdepth >= MAX_FOLDER_DEPTH) return; // limit the folder depth + strcat(currentfoldername, folder); + strcat(currentfoldername, "/"); + filelist.changeDir(folder); + refresh(); + folderdepth++; + currentindex = 0; + } + + void FileNavigator::upDIR() { + filelist.upDir(); + refresh(); + folderdepth--; + currentindex = 0; + // Remove the last child folder from the stored path + if (folderdepth == 0) { + currentfoldername[0] = '\0'; + reset(); + } + else { + char *pos = nullptr; + for (uint8_t f = 0; f < folderdepth; f++) + pos = strchr(currentfoldername, '/'); + + *(pos + 1) = '\0'; + } + #if ACDEBUG(AC_FILE) + SERIAL_ECHOLNPAIR("depth: ", folderdepth, " currentfoldername: ", currentfoldername); + #endif + } + + char* FileNavigator::getCurrentFolderName() { return currentfoldername; } +} + +#endif // ANYCUBIC_LCD_CHIRON diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h new file mode 100644 index 0000000..8e03614 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/FileNavigator.h @@ -0,0 +1,56 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +/** + * lcd/extui/lib/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(); + void reset(); + void getFiles(uint16_t); + void upDIR(); + void changeDIR(char *); + void sendFile(); + void refresh(); + char * getCurrentFolderName(); + private: + static FileList filelist; + static char currentfoldername[MAX_PATH_LEN]; + static uint16_t lastindex; + static uint8_t folderdepth; + static uint16_t currentindex; + }; + extern FileNavigator filenavigator; +} diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.cpp b/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.cpp new file mode 100644 index 0000000..f09c4db --- /dev/null +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.cpp @@ -0,0 +1,62 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/** + * lcd/extui/lib/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" + +#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; + uint16_t wholenotelen = tune[0] / speed; + do { + uint16_t freq = tune[pos]; + uint16_t 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/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/Tunes.h new file mode 100644 index 0000000..1bafec4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +/** + * lcd/extui/lib/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: * + * {<whole note time>,<note1>,<length1>, <note2>,<length2>, ... <END>} * + * * + * 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 <stdint.h> + +#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/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp new file mode 100644 index 0000000..61057b5 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.cpp @@ -0,0 +1,885 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/** + * lcd/extui/lib/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 "../../../../sd/cardreader.h" +#include "../../../../libs/numtostr.h" +#include "../../../../MarlinCore.h" + +namespace Anycubic { + + 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]; + char ChironTFT::panel_command[MAX_CMND_LEN]; + uint8_t ChironTFT::command_len; + float ChironTFT::live_Zoffset; + file_menu_t ChironTFT::file_menu; + + ChironTFT Chiron; + + ChironTFT::ChironTFT(){} + + void ChironTFT::Startup() { + selectedfile[0] = '\0'; + panel_command[0] = '\0'; + command_len = 0; + 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); + + // Signal Board has reset + SendtoTFTLN(AC_msg_main_board_has_reset); + + safe_delay(200); + + // 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_P(AC_cmnd_enable_leveling); + + // Startup tunes are defined in Tunes.h + //PlayTune(BEEPER_PIN, Anycubic_PowerOn, 1); + PlayTune(BEEPER_PIN, GB_PowerOn, 1); + #if ACDEBUGLEVEL + SERIAL_ECHOLNPAIR("AC Debug Level ", ACDEBUGLEVEL); + #endif + SendtoTFTLN(AC_msg_ready); + } + + void ChironTFT::IdleLoop() { + if (ReadTFTCommand()) { + ProcessPanelRequest(); + command_len = 0; + } + CheckHeaters(); + } + + void ChironTFT::PrinterKilled(PGM_P error,PGM_P component) { + SendtoTFTLN(AC_msg_kill_lcd); + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("PrinterKilled()\nerror: ", error , "\ncomponent: ", component); + #endif + } + + void ChironTFT::MediaEvent(media_event_t event) { + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("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: + SendtoTFTLN(AC_msg_no_sd_card); + break; + } + } + + void ChironTFT::TimerEvent(timer_event_t event) { + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("TimerEvent() ", event); + SERIAL_ECHOLNPAIR("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_ECHOLNPAIR("FilamentRunout() printer_state ", printer_state); + #endif + // 1 Signal filament out + SendtoTFTLN(isPrintingFromMedia() ? AC_msg_filament_out_alert : AC_msg_filament_out_block); + //printer_state = AC_printer_filament_out; + PlayTune(BEEPER_PIN, FilamentOut, 1); + } + + void ChironTFT::ConfirmationRequest(const char * const msg) { + // M108 continue + #if ACDEBUG(AC_MARLIN) + SERIAL_ECHOLNPAIR("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 timout, 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_ECHOLNPAIR("StatusChange() ", msg); + SERIAL_ECHOLNPAIR("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(CUSTOM_MACHINE_NAME), MARLIN_msg_ready) == 0) { + injectCommands_P(PSTR("M500\nG27")); + SendtoTFTLN(AC_msg_probing_complete); + printer_state = AC_printer_idle; + msg_matched = true; + } + // If probing fails dont 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_P(PSTR("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; + } + } + } + + void ChironTFT::PowerLossRecovery() { + printer_state = AC_printer_resuming_from_power_outage; // Play tune to notify user we can recover. + PlayTune(BEEPER_PIN, SOS, 1); + SERIAL_ECHOLNPGM("Resuming from power outage..."); + SERIAL_ECHOLNPGM("Select SD file then press resume"); + } + + void ChironTFT::SendtoTFT(PGM_P str) { // A helper to print PROGMEN string to the panel + #if ACDEBUG(AC_SOME) + serialprintPGM(str); + #endif + while (const char c = pgm_read_byte(str++)) TFTSer.print(c); + } + + void ChironTFT::SendtoTFTLN(PGM_P str = nullptr) { + if (str) { + #if ACDEBUG(AC_SOME) + SERIAL_ECHOPGM("> "); + #endif + SendtoTFT(str); + #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) { + panel_command[command_len] = 0x00; + #if ACDEBUG(AC_ALL) + SERIAL_ECHOLNPAIR("< ", panel_command); + #endif + #if ACDEBUG(AC_SOME) + // Ignore status request commands + uint8_t req = atoi(&panel_command[1]); + if (req > 7 && req != 20) { + SERIAL_ECHOLNPAIR("> ", panel_command); + SERIAL_ECHOLNPAIR("printer_state:", printer_state); + } + #endif + } + return command_ready; + } + + int8_t ChironTFT::Findcmndpos(const char * buff, char q) { + int8_t pos = 0; + do { if (buff[pos] == q) return pos; } while(++pos < MAX_CMND_LEN); + return -1; + } + + void ChironTFT::CheckHeaters() { + uint8_t faultDuration = 0; + float temp = 0; + + // if the hotend temp is abnormal, confirm state before signalling panel + 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); + SERIAL_ECHOLNPAIR("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); + SERIAL_ECHOLNPAIR("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), -1, 1)) { + 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), -0.5, 0.5)) { + 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_ECHOLNPAIR("## SendFileList ## ", startindex); + #endif + SendtoTFTLN(PSTR("FN ")); + filenavigator.getFiles(startindex); + SendtoTFTLN(PSTR("END")); + } + + void ChironTFT::SelectFile() { + strncpy(selectedfile, panel_command + 4, command_len - 4); + selectedfile[command_len - 5] = '\0'; + #if ACDEBUG(AC_FILE) + SERIAL_ECHOLNPAIR_F(" 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 + filenavigator.changeDIR(selectedfile); + SendtoTFTLN(AC_msg_sd_file_open_failed); + SendFileList( 0 ); + break; + } + } + + void ChironTFT::InjectCommandandWait(PGM_P cmd) { + //injectCommands_P(cmnd); queue.enqueue_now_P(cmd); + //SERIAL_ECHOLN(PSTR("Inject>")); + } + + void ChironTFT::ProcessPanelRequest() { + // Break these up into logical blocks // as its easier to navigate than one huge switch case! + int8_t req = atoi(&panel_command[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 <= 34) PanelProcess(req); + + else SendtoTFTLN(); + } + + void ChironTFT::PanelInfo(uint8_t req) { + // information requests A0-A8 and A33 + switch (req) { + case 0: // A0 Get HOTEND Temp + SendtoTFT(PSTR("A0V ")); + TFTSer.println(getActualTemp_celsius(E0)); + break; + + case 1: // A1 Get HOTEND Target Temp + SendtoTFT(PSTR("A1V ")); + TFTSer.println(getTargetTemp_celsius(E0)); + break; + + case 2: // A2 Get BED Temp + SendtoTFT(PSTR("A2V ")); + TFTSer.println(getActualTemp_celsius(BED)); + break; + + case 3: // A3 Get BED Target Temp + SendtoTFT(PSTR("A3V ")); + TFTSer.println(getTargetTemp_celsius(BED)); + break; + + case 4: // A4 Get FAN Speed + SendtoTFT(PSTR("A4V ")); + TFTSer.println(getActualFan_percent(FAN0)); + break; + + case 5: // A5 Get Current Coordinates + SendtoTFT(PSTR("A5V X: ")); + TFTSer.print(getAxisPosition_mm(X)); + SendtoTFT(PSTR(" Y: ")); + TFTSer.print(getAxisPosition_mm(Y)); + SendtoTFT(PSTR(" Z: ")); + TFTSer.println(getAxisPosition_mm(Z)); + break; + + case 6: // A6 Get printing progress + if (isPrintingFromMedia()) { + SendtoTFT(PSTR("A6V ")); + TFTSer.println(ui8tostr2(getProgress_percent())); + } + else + SendtoTFTLN(PSTR("A6V ---")); + break; + + case 7: { // A7 Get Printing Time + uint32_t time = getProgress_seconds_elapsed() / 60; + SendtoTFT(PSTR("A7V ")); + TFTSer.print(ui8tostr2(time / 60)); + SendtoTFT(PSTR(" H ")); + TFTSer.print(ui8tostr2(time % 60)); + SendtoTFT(PSTR(" M")); + #if ACDEBUG(AC_ALL) + SERIAL_ECHOLNPAIR("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(PSTR("J33 ")); + SendtoTFTLN(PSTR(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_P(PSTR("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 dont want to recover + if (printer_state == AC_printer_resuming_from_power_outage) { + injectCommands_P(PSTR("M1000 C")); // Cancel recovery + printer_state = AC_printer_idle; + } + #if ACDebugLevel >= 1 + SERIAL_ECHOLNPAIR_F("Print: ", selectedfile); + #endif + // the card library needs a path starting // but the File api doesn't... + char file[MAX_PATH_LEN]; + file[0] = '/'; + strcpy(file + 1, selectedfile); + printFile(file); + 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("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()) { + disable_all_steppers(); // from marlincore.h + 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(PSTR("A20V ")); + TFTSer.println(getFeedrate_percent()); + } + break; + + case 21: // A21 Home Axis A21 X + if (!isPrinting()) { + switch ((char)panel_command[4]) { + case 'X': injectCommands_P(PSTR("G28X")); break; + case 'Y': injectCommands_P(PSTR("G28Y")); break; + case 'Z': injectCommands_P(PSTR("G28Z")); break; + case 'C': injectCommands_P(G28_STR); break; + } + } + break; + + case 22: // A22 Move Axis A22 Y +10F3000 + // Ignore request if printing + if (!isPrinting()) { + // setAxisPosition_mm() uses pre defined manual feedrates so ignore the feedrate from the panel + setSoftEndstopState(true); // enable endstops + float newposition = atof(&panel_command[6]); + + #if ACDEBUG(AC_ACTION) + SERIAL_ECHOLNPAIR("Nudge ", panel_command[4], " axis ", newposition); + #endif + + switch (panel_command[4]) { + case 'X': setAxisPosition_mm(getAxisPosition_mm(X) + newposition, X); break; + case 'Y': setAxisPosition_mm(getAxisPosition_mm(Y) + newposition, Y); break; + case 'Z': setAxisPosition_mm(getAxisPosition_mm(Z) + newposition, Z); break; + case 'E': // The only time we get this command is from the filament load/unload menu + // the standard movement is too slow so we will use the load unlod GCode to speed it up a bit + if (canMove(E0) && !commandsInQueue()) + injectCommands_P(newposition > 0 ? AC_cmnd_manual_load_filament : AC_cmnd_manual_unload_filament); + break; + } + } + 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 + // M22 M21 maybe needed here to reset sd card + 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[5]); + pos.y = atoi(&panel_command[8]); + pos_z = getMeshPoint(pos); + + SendtoTFT(PSTR("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_ECHOLNPAIR("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_ECHOLNPAIR("Current Z: ", getAxisPosition_mm(Z)); + #endif + } + } + selectedmeshpoint.x = pos.x; + selectedmeshpoint.y = pos.y; + } + } break; + + case 30: { // A30 Auto leveling + if (panel_command[3] == 'S') { // Start probing + // Ignore request if printing + if (isPrinting()) + SendtoTFTLN(AC_msg_probing_not_allowed); // forbid auto leveling + else { + injectCommands_P(PSTR("G28O\nG29")); + printer_state = AC_printer_probing; + SendtoTFTLN(AC_msg_start_probing); + } + } + else SendtoTFTLN(AC_msg_start_probing); + } break; + + case 31: { // A31 Adjust all Probe Points + switch (panel_command[3]) { + case 'C': // Restore and apply original offsets + if (!isPrinting()) { + injectCommands_P(PSTR("M501\nM420 S1")); + selectedmeshpoint.x = selectedmeshpoint.y = 99; + } + break; + case 'D': // Save Z Offset tables and restore leveling state + if (!isPrinting()) { + setAxisPosition_mm(1.0,Z); + injectCommands_P(PSTR("M500")); + selectedmeshpoint.x = selectedmeshpoint.y = 99; + } + break; + case 'G': // Get current offset + SendtoTFT(PSTR("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; + } + break; + case 'S': { // Set offset (adjusts all points by value) + float Zshift = atof(&panel_command[4]); + 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_ECHOLNPAIR("Change Zoffset from:", live_Zoffset, " to ", live_Zoffset + Zshift); + #endif + if (isAxisPositionKnown(Z)) { + #if ACDEBUG(AC_INFO) + const float currZpos = getAxisPosition_mm(Z); + SERIAL_ECHOLNPAIR("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_ECHOLNPAIR("Steps to move Z: ", steps); + #endif + babystepAxis_steps(steps, Z); + live_Zoffset += Zshift; + } + SendtoTFT(PSTR("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)); + } + const float currZOffset = getZOffset_mm(); + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("Change probe offset from ", currZOffset, " to ", currZOffset + Zshift); + #endif + + setZOffset_mm(currZOffset + Zshift); + SendtoTFT(PSTR("A31V ")); + TFTSer.println(getZOffset_mm()); + + if (isAxisPositionKnown(Z)) { + // Move Z axis + const float currZpos = getAxisPosition_mm(Z); + #if ACDEBUG(AC_INFO) + SERIAL_ECHOLNPAIR("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; + } // end switch + } break; + + case 32: { // A32 clean leveling beep flag + // Ignore request if printing + //if (isPrinting()) break; + //injectCommands_P(PSTR("M500\nM420 S1\nG1 Z10 F240\nG1 X0 Y0 F6000")); + //TFTSer.println(""); + } break; + + // A33 firmware info request seet PanelInfo() + + case 34: { // A34 Adjust single mesh point A34 C/S X1 Y1 V123 + if (panel_command[3] == 'C') { // Restore original offsets + injectCommands_P(PSTR("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_ECHOLNPAIR("Change mesh point x:", pos.x, " y:", pos.y); + SERIAL_ECHOLNPAIR("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_ECHOLNPAIR("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; + } + } +} // namespace + +#endif // ANYCUBIC_LCD_CHIRON diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h new file mode 100644 index 0000000..267f2fe --- /dev/null +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft.h @@ -0,0 +1,77 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +/** + * lcd/extui/lib/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" +namespace Anycubic { + + class ChironTFT { + 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]; + static uint8_t command_len; + static char selectedfile[MAX_PATH_LEN]; + static float live_Zoffset; + static file_menu_t file_menu; + public: + ChironTFT(); + void Startup(); + void IdleLoop(); + void PrinterKilled(PGM_P,PGM_P); + void MediaEvent(media_event_t); + void TimerEvent(timer_event_t); + void FilamentRunout(); + void ConfirmationRequest(const char * const ); + void StatusChange(const char * const ); + void PowerLossRecovery(); + + private: + void SendtoTFT(PGM_P); + void SendtoTFTLN(PGM_P); + bool ReadTFTCommand(); + int8_t Findcmndpos(const char *, char); + void CheckHeaters(); + void SendFileList(int8_t); + void SelectFile(); + void InjectCommandandWait(PGM_P); + void ProcessPanelRequest(); + void PanelInfo(uint8_t); + void PanelAction(uint8_t); + void PanelProcess(uint8_t); + }; + + extern ChironTFT Chiron; + +} diff --git a/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h new file mode 100644 index 0000000..7012e98 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/anycubic_chiron/chiron_tft_defs.h @@ -0,0 +1,151 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/** + * lcd/extui/lib/chiron_defs.h + * + * Extensible_UI implementation for Anycubic Chiron + * Written By Nick Wells, 2020 [https://github.com/SwiftNick] + * (not affiliated with Anycubic, Ltd.) + */ + +#pragma once +#include "../../../../inc/MarlinConfigPre.h" +//#define ACDEBUGLEVEL 255 + +#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 Z_PROBE_LOW_POINT // The lowest value you can set for a single mesh point offset + + // TFT panel commands +#define AC_msg_sd_card_inserted PSTR("J00") +#define AC_msg_sd_card_removed PSTR("J01") +#define AC_msg_no_sd_card PSTR("J02") +#define AC_msg_usb_connected PSTR("J03") +#define AC_msg_print_from_sd_card PSTR("J04") +#define AC_msg_pause PSTR("J05") +#define AC_msg_nozzle_heating PSTR("J06") +#define AC_msg_nozzle_heating_done PSTR("J07") +#define AC_msg_bed_heating PSTR("J08") +#define AC_msg_bed_heating_done PSTR("J09") +#define AC_msg_nozzle_temp_abnormal PSTR("J10") +#define AC_msg_kill_lcd PSTR("J11") +#define AC_msg_ready PSTR("J12") +#define AC_msg_low_nozzle_temp PSTR("J13") +#define AC_msg_print_complete PSTR("J14") +#define AC_msg_filament_out_alert PSTR("J15") +#define AC_msg_stop PSTR("J16") +#define AC_msg_main_board_has_reset PSTR("J17") +#define AC_msg_paused PSTR("J18") +#define AC_msg_j19_unknown PSTR("J19") +#define AC_msg_sd_file_open_success PSTR("J20") +#define AC_msg_sd_file_open_failed PSTR("J21") +#define AC_msg_level_monitor_finished PSTR("J22") +#define AC_msg_filament_out_block PSTR("J23") +#define AC_msg_probing_not_allowed PSTR("J24") +#define AC_msg_probing_complete PSTR("J25") +#define AC_msg_start_probing PSTR("J26") +#define AC_msg_version PSTR("J27") + +#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_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 PSTR("M701") // Use Marlin unload routine +#define AC_cmnd_auto_load_filament PSTR("M702 M0 PB") // Use Marlin load routing then pause for user to clean nozzle + +#define AC_cmnd_manual_load_filament PSTR("M83\nG1 E50 F700\nM82") // replace the manual panel commands with something a little faster +#define AC_cmnd_manual_unload_filament PSTR("M83\nG1 E-50 F1200\nM82") +#define AC_cmnd_enable_leveling PSTR("M420SV") +#define AC_cmnd_power_loss_recovery PSTR("G28XYR5\nG28Z") // Lift, home X and Y then home Z when in 'safe' position + +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_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 + }; +} diff --git a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp new file mode 100644 index 0000000..1508dc0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.cpp @@ -0,0 +1,1028 @@ +/** + * anycubic_i3mega_lcd.cpp --- Support for Anycubic i3 Mega TFT + * Created by Christian Hopp on 09.12.17. + * Improved by David Ramiro + * Converted to ext_iu 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/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) (sendLine_P(PSTR(x)), SERIAL_ECHOLNPGM(y)) + #define SENDLINE_DBG_PGM_VAL(x,y,z) (sendLine_P(PSTR(x)), SERIAL_ECHOPGM(y), SERIAL_ECHOLN(z)) +#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; + +static void sendNewLine(void) { + LCD_SERIAL.write('\r'); + LCD_SERIAL.write('\n'); +} + +static void send(const char *str) { + LCD_SERIAL.print(str); +} + +static void sendLine(const char *str) { + send(str); + sendNewLine(); +} + +static void send_P(PGM_P str) { + while (const char c = pgm_read_byte(str++)) + LCD_SERIAL.write(c); +} + +static void sendLine_P(PGM_P str) { + send_P(str); + sendNewLine(); +} + +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 + ExtUI::delay_ms(10); + + // initialise the state of the key pins running on the tft + #if ENABLED(SDSUPPORT) && PIN_EXISTS(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 + ExtUI::delay_ms(10); + + DoFilamentRunoutCheck(); + SelectedFile[0] = 0; + + #if ENABLED(STARTUP_CHIME) + ExtUI::injectCommands_P(PSTR("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; + ExtUI::injectCommands_P(PSTR("M84\nM27")); // disable stepper motors and force report of SD status + ExtUI::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_ECHOPGM("TFT Serial Debug: OnSDCardStateChange event triggered..."); + SERIAL_ECHO(ui8tostr2(isInserted)); + SERIAL_EOL(); + #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_ECHOPGM("TFT Serial Debug: OnUserConfirmRequired triggered... "); + SERIAL_ECHOLN(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 = ExtUI::getAxisPosition_mm((ExtUI::axis_t) ExtUI::X); + const float yPosition = ExtUI::getAxisPosition_mm((ExtUI::axis_t) ExtUI::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': // "<exit>" + 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"); + ExtUI::injectCommands_P(PSTR("G91\nG1 Z+0.1\nG90")); + break; + + case '2': // "<02ZUp0.02>" + SERIAL_ECHOLNPGM("Special Menu: Z Up 0.02"); + ExtUI::injectCommands_P(PSTR("G91\nG1 Z+0.02\nG90")); + break; + + case '3': // "<03ZDn0.02>" + SERIAL_ECHOLNPGM("Special Menu: Z Down 0.02"); + ExtUI::injectCommands_P(PSTR("G91\nG1 Z-0.02\nG90")); + break; + + case '4': // "<04ZDn0.1>" + SERIAL_ECHOLNPGM("Special Menu: Z Down 0.1"); + ExtUI::injectCommands_P(PSTR("G91\nG1 Z-0.1\nG90")); + break; + + case '5': // "<05PrehtBed>" + SERIAL_ECHOLNPGM("Special Menu: Preheat Bed"); + ExtUI::injectCommands_P(PSTR("M140 S65")); + break; + + case '6': // "<06SMeshLvl>" + SERIAL_ECHOLNPGM("Special Menu: Start Mesh Leveling"); + ExtUI::injectCommands_P(PSTR("G29S1")); + break; + + case '7': // "<07MeshNPnt>" + SERIAL_ECHOLNPGM("Special Menu: Next Mesh Point"); + ExtUI::injectCommands_P(PSTR("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 + ExtUI::injectCommands_P(PSTR("M106 S204\nG4 P500\nM303 E0 S215 C15 U1")); + break; + + case '9': // "<09HtBedPID>" + SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotbed Pid"); + ExtUI::injectCommands_P(PSTR("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"); + ExtUI::injectCommands_P(PSTR("M502\nM300 P105 S1661\nM300 P210 S1108")); + break; + + case '1': // "<11SvEEPROM>" + SERIAL_ECHOLNPGM("Special Menu: Save EEPROM"); + ExtUI::injectCommands_P(PSTR("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"); + ExtUI::injectCommands_P(PSTR("M140 S65")); + break; + + case '2': // "<02ABL>" + SERIAL_ECHOLNPGM("Special Menu: Auto Bed Leveling"); + ExtUI::injectCommands_P(PSTR("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 + ExtUI::injectCommands_P(PSTR("M106 S204\nG4 P500\nM303 E0 S215 C15 U1")); + break; + + case '4': // "<04HtbedPID>" + SERIAL_ECHOLNPGM("Special Menu: Auto Tune Hotbed Pid"); + ExtUI::injectCommands_P(PSTR("M303 E-1 S65 C6 U1")); + break; + + case '5': // "<05FWDeflts>" + SERIAL_ECHOLNPGM("Special Menu: Load FW Defaults"); + ExtUI::injectCommands_P(PSTR("M502\nM300 P105 S1661\nM300 P210 S1108")); + break; + + case '6': // "<06SvEEPROM>" + SERIAL_ECHOLNPGM("Special Menu: Save EEPROM"); + ExtUI::injectCommands_P(PSTR("M500\nM300 P105 S1108\nM300 P210 S1661")); + break; + + case '7': // <07SendM108> + SERIAL_ECHOLNPGM("Special Menu: Send User Confirmation"); + ExtUI::injectCommands_P(PSTR("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; + ExtUI::FileList currentFileList; + + SENDLINE_PGM("FN "); // Filelist start + + if (!ExtUI::isMediaInserted() && !SpecialMenu) { + SENDLINE_DBG_PGM("J02", "TFT Serial Debug: No SD Card mounted to render Current File List... J02"); + + SENDLINE_PGM("<Special_Menu>"); + SENDLINE_PGM("<Special_Menu>"); + } + 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("<Z Up 0.1>"); + SENDLINE_PGM("<02ZUp0.02>"); + SENDLINE_PGM("<Z Up 0.02>"); + SENDLINE_PGM("<03ZDn0.02>"); + SENDLINE_PGM("<Z Down 0.02>"); + SENDLINE_PGM("<04ZDn0.1>"); + SENDLINE_PGM("<Z Down 0.1>"); + break; + + case 4: // Second Page + SENDLINE_PGM("<05PrehtBed>"); + SENDLINE_PGM("<Preheat bed>"); + SENDLINE_PGM("<06SMeshLvl>"); + SENDLINE_PGM("<Start Mesh Leveling>"); + SENDLINE_PGM("<07MeshNPnt>"); + SENDLINE_PGM("<Next Mesh Point>"); + SENDLINE_PGM("<08HtEndPID>"); + SENDLINE_PGM("<Auto Tune Hotend PID>"); + break; + + case 8: // Third Page + SENDLINE_PGM("<09HtBedPID>"); + SENDLINE_PGM("<Auto Tune Hotbed PID>"); + SENDLINE_PGM("<10FWDeflts>"); + SENDLINE_PGM("<Load FW Defaults>"); + SENDLINE_PGM("<11SvEEPROM>"); + SENDLINE_PGM("<Save EEPROM>"); + SENDLINE_PGM("<Exit>"); + SENDLINE_PGM("<Exit>"); + break; + #else + case 0: // First Page + SENDLINE_PGM("<01PrehtBed>"); + SENDLINE_PGM("<Preheat bed>"); + SENDLINE_PGM("<02ABL>"); + SENDLINE_PGM("<Auto Bed Leveling>"); + SENDLINE_PGM("<03HtEndPID>"); + SENDLINE_PGM("<Auto Tune Hotend PID>"); + SENDLINE_PGM("<04HtBedPID>"); + SENDLINE_PGM("<Auto Tune Hotbed PID>"); + break; + + case 4: // Second Page + SENDLINE_PGM("<05FWDeflts>"); + SENDLINE_PGM("<Load FW Defaults>"); + SENDLINE_PGM("<06SvEEPROM>"); + SENDLINE_PGM("<Save EEPROM>"); + SENDLINE_PGM("<07SendM108>"); + SENDLINE_PGM("<Send User Confirmation>"); + SENDLINE_PGM("<Exit>"); + SENDLINE_PGM("<Exit>"); + break; + + #endif // PROBE_MANUALLY + + default: + break; + } +} + +void AnycubicTFTClass::RenderCurrentFolder(uint16_t selectedNumber) { + ExtUI::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("<specialmnu>"); + SENDLINE_PGM("<Special Menu>"); + } + 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 (ExtUI::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 +} + +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_ECHOPGM("TFT Serial Command: "); + SERIAL_ECHOLN(TFTcmdbuffer[TFTbufindw]); + } + #endif + + switch (a_command) { + case 0: { // A0 GET HOTEND TEMP + float hotendActualTemp = ExtUI::getActualTemp_celsius((ExtUI::extruder_t) (ExtUI::extruder_t) ExtUI::E0); + SEND_PGM_VAL("A0V ", int(hotendActualTemp + 0.5)); + } + break; + + case 1: { // A1 GET HOTEND TARGET TEMP + float hotendTargetTemp = ExtUI::getTargetTemp_celsius((ExtUI::extruder_t) (ExtUI::extruder_t) ExtUI::E0); + SEND_PGM_VAL("A1V ", int(hotendTargetTemp + 0.5)); + } + break; + + case 2: { // A2 GET HOTBED TEMP + float heatedBedActualTemp = ExtUI::getActualTemp_celsius((ExtUI::heater_t) ExtUI::BED); + SEND_PGM_VAL("A2V ", int(heatedBedActualTemp + 0.5)); + } + break; + + case 3: { // A3 GET HOTBED TARGET TEMP + float heatedBedTargetTemp = ExtUI::getTargetTemp_celsius((ExtUI::heater_t) ExtUI::BED); + SEND_PGM_VAL("A3V ", int(heatedBedTargetTemp + 0.5)); + } break; + + case 4: { // A4 GET FAN SPEED + float fanPercent = ExtUI::getActualFan_percent(ExtUI::FAN0); + fanPercent = constrain(fanPercent, 0, 100); + SEND_PGM_VAL("A4V ", int(fanPercent)); + } break; + + case 5: { // A5 GET CURRENT COORDINATE + const float xPosition = ExtUI::getAxisPosition_mm(ExtUI::X), + yPosition = ExtUI::getAxisPosition_mm(ExtUI::Y), + zPosition = ExtUI::getAxisPosition_mm(ExtUI::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 (ExtUI::isPrintingFromMedia()) { + SEND_PGM("A6V "); + if (ExtUI::isMediaInserted()) + SENDLINE(ui8tostr3rj(ExtUI::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 = ExtUI::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 (ExtUI::isPrintingFromMedia()) + PausePrint(); + #endif + break; + + case 10: // A10 resume sd print + #if ENABLED(SDSUPPORT) + if (ExtUI::isPrintingFromMediaPaused()) + ResumePrint(); + #endif + break; + + case 11: // A11 STOP SD PRINT + TERN_(SDSUPPORT, StopPrint()); + break; + + case 12: // A12 kill + kill(PSTR(STR_ERR_KILLED)); + break; + + case 13: // A13 SELECTION FILE + #if ENABLED(SDSUPPORT) + if (ExtUI::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 (!ExtUI::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); + ExtUI::setTargetTemp_celsius(tempvalue, (ExtUI::extruder_t) ExtUI::E0); + } + else if (CodeSeen('C') && !ExtUI::isPrinting()) { + if (ExtUI::getAxisPosition_mm(ExtUI::Z) < 10) + ExtUI::injectCommands_P(PSTR("G1 Z10")); // RASE Z AXIS + tempvalue = constrain(CodeValue(), 0, 275); + ExtUI::setTargetTemp_celsius(tempvalue, (ExtUI::extruder_t) ExtUI::E0); + } + } + break; + + case 17: { // A17 set heated bed temp + unsigned int tempbed; + if (CodeSeen('S')) { + tempbed = constrain(CodeValue(), 0, 100); + ExtUI::setTargetTemp_celsius(tempbed, (ExtUI::heater_t)ExtUI::BED); + } + } + break; + + case 18: { // A18 set fan speed + float fanPercent; + if (CodeSeen('S')) { + fanPercent = CodeValue(); + fanPercent = constrain(fanPercent, 0, 100); + ExtUI::setTargetFan_percent(fanPercent, ExtUI::FAN0); + } + else + fanPercent = 100; + + ExtUI::setTargetFan_percent(fanPercent, ExtUI::FAN0); + SENDLINE_PGM(""); + } + break; + + case 19: // A19 stop stepper drivers - sent on stop extrude command and on turn motors off command + if (!ExtUI::isPrinting()) { + quickstop_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 (!ExtUI::isPrinting() && !ExtUI::isPrintingFromMediaPaused()) { + if (CodeSeen('X') || CodeSeen('Y') || CodeSeen('Z')) { + if (CodeSeen('X')) + ExtUI::injectCommands_P(PSTR("G28X")); + if (CodeSeen('Y')) + ExtUI::injectCommands_P(PSTR("G28Y")); + if (CodeSeen('Z')) + ExtUI::injectCommands_P(PSTR("G28Z")); + } + else if (CodeSeen('C')) { + ExtUI::injectCommands_P(G28_STR); + } + } + break; + + case 22: // A22 move X/Y/Z or extrude + if (!ExtUI::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 + ExtUI::injectCommands(fullCommandStr); + } + } + SENDLINE_PGM(""); + break; + + case 23: // A23 preheat pla + if (!ExtUI::isPrinting()) { + if (ExtUI::getAxisPosition_mm(ExtUI::Z) < 10) + ExtUI::injectCommands_P(PSTR("G1 Z10")); // RASE Z AXIS + + ExtUI::setTargetTemp_celsius(PREHEAT_1_TEMP_BED, (ExtUI::heater_t) ExtUI::BED); + ExtUI::setTargetTemp_celsius(PREHEAT_1_TEMP_HOTEND, (ExtUI::extruder_t) ExtUI::E0); + SENDLINE_PGM("OK"); + } + break; + + case 24:// A24 preheat abs + if (!ExtUI::isPrinting()) { + if (ExtUI::getAxisPosition_mm(ExtUI::Z) < 10) + ExtUI::injectCommands_P(PSTR("G1 Z10")); // RASE Z AXIS + + ExtUI::setTargetTemp_celsius(PREHEAT_2_TEMP_BED, (ExtUI::heater_t) ExtUI::BED); + ExtUI::setTargetTemp_celsius(PREHEAT_2_TEMP_HOTEND, (ExtUI::extruder_t) ExtUI::E0); + SENDLINE_PGM("OK"); + } + break; + + case 25: // A25 cool down + if (!ExtUI::isPrinting()) { + ExtUI::setTargetTemp_celsius(0, (ExtUI::heater_t) ExtUI::BED); + ExtUI::setTargetTemp_celsius(0, (ExtUI::extruder_t) ExtUI::E0); + + SENDLINE_DBG_PGM("J12", "TFT Serial Debug: Cooling down... J12"); // J12 cool down + } + break; + + case 26: // A26 refresh SD + #if ENABLED(SDSUPPORT) + if (ExtUI::isMediaInserted()) { + if (strlen(SelectedDirectory) > 0) { + ExtUI::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 ENABLED(SDSUPPORT) && PIN_EXISTS(SD_DETECT) + bool isInserted = ExtUI::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: ExtUI::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 + ExtUI::injectCommands_P(PSTR("\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 (!ExtUI::isPrinting() && strlen(SelectedFile) > 0) { + #if ENABLED(ANYCUBIC_LCD_DEBUG) + SERIAL_ECHOPGM("TFT Serial Debug: About to print file ... "); + SERIAL_ECHO(ExtUI::isPrinting()); + SERIAL_ECHOPGM(" "); + SERIAL_ECHOLN(SelectedFile); + #endif + mediaPrintingState = AMPRINTSTATE_PRINTING; + mediaPauseState = AMPAUSESTATE_NOT_PAUSED; + ExtUI::printFile(SelectedFile); + } + #endif // SDUPPORT +} + +void AnycubicTFTClass::PausePrint() { + #if ENABLED(SDSUPPORT) + if (ExtUI::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 + ExtUI::injectCommands_P(PSTR("G91\nG1 E-2 F1800\nG90")); + ExtUI::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 + ExtUI::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 + ExtUI::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 + ExtUI::injectCommands_P(PSTR("G91\nG1 E-2 F1800\nG90")); + ExtUI::stopPrint(); + #endif +} + +#endif // ANYCUBIC_LCD_I3MEGA diff --git a/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h new file mode 100644 index 0000000..59050ac --- /dev/null +++ b/Marlin/src/lcd/extui/lib/anycubic_i3mega/anycubic_i3mega_lcd.h @@ -0,0 +1,97 @@ +/** + * anycubic_i3mega_lcd.h --- Support for Anycubic i3 Mega TFT + * Created by Christian Hopp on 09.12.17. + * Improved by David Ramiro + * Converted to ext_iu 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_FIAMENT_PRUGING, + AMPAUSESTATE_HEATER_TIMEOUT, + AMPAUSESTATE_REHEATING, + AMPAUSESTATE_REHEAT_FINISHED +}; + +class AnycubicTFTClass { +public: + AnycubicTFTClass(); + void OnSetup(); + void OnCommandScan(); + void OnKillTFT(); + void OnSDCardStateChange(bool); + void OnSDCardError(); + void OnFilamentRunout(); + void OnUserConfirmRequired(const char *); + void OnPrintTimerStarted(); + void OnPrintTimerPaused(); + void OnPrintTimerStopped(); + +private: + char TFTcmdbuffer[TFTBUFSIZE][TFT_MAX_CMD_SIZE]; + int TFTbuflen=0; + int TFTbufindr = 0; + int TFTbufindw = 0; + char serial3_char; + int serial3_count = 0; + char *TFTstrchr_pointer; + uint8_t SpecialMenu = false; + AnycubicMediaPrintState mediaPrintingState = AMPRINTSTATE_NOT_PRINTING; + AnycubicMediaPauseState mediaPauseState = AMPAUSESTATE_NOT_PAUSED; + + float CodeValue(); + bool CodeSeen(char); + bool IsNozzleHomed(); + void RenderCurrentFileList(); + void RenderSpecialMenu(uint16_t); + void RenderCurrentFolder(uint16_t); + void GetCommandFromTFT(); + void CheckSDCardChange(); + void CheckPauseState(); + void CheckPrintCompletion(); + void HandleSpecialMenu(); + void DoSDCardStateCheck(); + void DoFilamentRunoutCheck(); + void StartPrint(); + void PausePrint(); + void ResumePrint(); + void StopPrint(); + + char SelectedDirectory[30]; + char SelectedFile[FILENAME_LENGTH]; +}; + +extern AnycubicTFTClass AnycubicTFT; +extern const char G28_STR[]; diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp new file mode 100644 index 0000000..c7cd767 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.cpp @@ -0,0 +1,261 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/* DGUS implementation written by coldtobi in 2019 for Marlin */ + +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_DGUS_LCD + +#if HOTENDS > 2 + #error "More than 2 hotends not implemented on the Display UI design." +#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" + +// 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())) + 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<const char*>(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<const void*>(&value), sizeof(uint16_t)); +} + +void DGUSDisplay::WriteVariable(uint16_t adr, int16_t value) { + value = (value & 0xffU) << 8U | (value >> 8U); + WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint16_t)); +} + +void DGUSDisplay::WriteVariable(uint16_t adr, uint8_t value) { + WriteVariable(adr, static_cast<const void*>(&value), sizeof(uint8_t)); +} + +void DGUSDisplay::WriteVariable(uint16_t adr, int8_t value) { + WriteVariable(adr, static_cast<const void*>(&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<const void*>(&tmp), sizeof(long)); +} + +void DGUSDisplay::WriteVariablePGM(uint16_t adr, const void* values, uint8_t valueslen, bool isstr) { + const char* myvalues = static_cast<const char*>(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(); + //DEBUG_ECHOPAIR("< ",x); + 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_ECHOPAIR(" ",x); + 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_ECHOPAIR(" (", 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_ECHOPAIR("# ", 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_ECHOPAIR(" ", 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_CMD_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_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_ECHOPAIR(" 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_ECHOLNPAIR(" 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 gcode 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; +bool 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_ECHOPAIR("populate_VPVar ", VP); + const DGUS_VP_Variable *pvp = DGUSLCD_FindVPVar(VP); + // DEBUG_ECHOLNPAIR(" pvp ", (uint16_t )pvp); + if (!pvp) return false; + memcpy_P(ramcopy, pvp, sizeof(DGUS_VP_Variable)); + return true; +} + +#endif // HAS_DGUS_LCD diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h new file mode 100644 index 0000000..88c1195 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplay.h @@ -0,0 +1,118 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +/* DGUS implementation written by coldtobi in 2019 for Marlin */ + +#include "../../../../inc/MarlinConfigPre.h" + +#include <stdlib.h> // size_t + +#if HAS_BED_PROBE + #include "../../../../module/probe.h" +#endif +#include "DGUSVPVariable.h" + +enum DGUSLCD_Screens : uint8_t; + +#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; + +// 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<typename T, float(*Getter)(const T), T selector, typename WireType=uint16_t> + static void SetVariable(DGUS_VP_Variable &var) { + WriteVariable(var.VP, (WireType)Getter(selector)); + } + + template<typename T, void(*Setter)(const float V, const T), T selector> + 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 initiliazed it. + // (both boils down that the display answered to our chatting) + static inline 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 inline uint16_t swap16(const uint16_t value) { return (value & 0xFFU) << 8U | (value >> 8U); } + static rx_datagram_state_t rx_datagram_state; + static uint8_t rx_datagram_len; + static bool Initialized, no_reentrance; +}; + +#define GET_VARIABLE(f, t, V...) (&DGUSDisplay::GetVariable<decltype(t), f, t, ##V>) +#define SET_VARIABLE(f, t, V...) (&DGUSDisplay::SetVariable<decltype(t), f, t, ##V>) + +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); } + +/// Find the flash address of a DGUS_VP_Variable for the VP. +extern 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. +extern bool populate_VPVar(const uint16_t VP, DGUS_VP_Variable * const ramcopy); diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSDisplayDef.h b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplayDef.h new file mode 100644 index 0000000..b34a048 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/dgus/DGUSDisplayDef.h @@ -0,0 +1,54 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +/* DGUS implementation written by coldtobi in 2019 for Marlin */ + +#include "DGUSVPVariable.h" + +#include <stdint.h> + +// This file defines the interaction between Marlin and the display firmware. + +// 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_FYSETC) + #include "fysetc/DGUSDisplayDef.h" +#elif ENABLED(DGUS_LCD_UI_HIPRECY) + #include "hiprecy/DGUSDisplayDef.h" +#endif diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.cpp b/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.cpp new file mode 100644 index 0000000..77feacf --- /dev/null +++ b/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.cpp @@ -0,0 +1,1140 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_DGUS_LCD + +#include "DGUSScreenHandler.h" +#include "DGUSDisplay.h" +#include "DGUSVPVariable.h" +#include "DGUSDisplayDef.h" + +#include "../../ui_api.h" +#include "../../../../MarlinCore.h" +#include "../../../../module/temperature.h" +#include "../../../../module/motion.h" +#include "../../../../gcode/queue.h" +#include "../../../../module/planner.h" +#include "../../../../sd/cardreader.h" +#include "../../../../libs/duration_t.h" +#include "../../../../module/printcounter.h" + +#if ENABLED(POWER_LOSS_RECOVERY) + #include "../../../../feature/powerloss.h" +#endif + +uint16_t DGUSScreenHandler::ConfirmVP; + +#if ENABLED(SDSUPPORT) + int16_t DGUSScreenHandler::top_file = 0; + int16_t DGUSScreenHandler::file_to_print = 0; + static ExtUI::FileList filelist; +#endif + +void (*DGUSScreenHandler::confirm_action_cb)() = nullptr; + +//DGUSScreenHandler ScreenHandler; + +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; + +//DGUSDisplay dgusdisplay; + +// endianness swap +uint16_t swap16(const uint16_t value) { return (value & 0xffU) << 8U | (value >> 8U); } + +void DGUSScreenHandler::sendinfoscreen(const char* line1, const char* line2, const char* line3, const char* 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); + } + if (populate_VPVar(VP_MSGSTR4, &ramcopy)) { + ramcopy.memadr = (void*) line4; + l4inflash ? DGUSScreenHandler::DGUSLCD_SendStringToDisplayPGM(ramcopy) : DGUSScreenHandler::DGUSLCD_SendStringToDisplay(ramcopy); + } +} + +void DGUSScreenHandler::HandleUserConfirmationPopUp(uint16_t VP, const char* line1, const char* line2, const char* line3, const char* 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); + ScreenHandler.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_ECHOPAIR(" DGUS_LCD_SendWordValueToDisplay ", var.VP); + //DEBUG_ECHOLNPAIR(" 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_ECHOPAIR(" DGUS_LCD_SendWordValueToDisplay ", var.VP); + //DEBUG_ECHOLNPAIR(" 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_ECHOPAIR(" DGUSLCD_SendPrintProgressToDisplay ", var.VP); + uint16_t tmp = ExtUI::getProgress_percent(); + //DEBUG_ECHOLNPAIR(" 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); + *(uint8_t*)var.memadr = map(constrain(value, 0, 100), 0, 100, 0, 255); + } +} + +// 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; + float valuesend = 0; + switch (var.VP) { + default: return; + #if HOTENDS >= 1 + 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 HOTENDS >= 2 + 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_ECHOPAIR(" DGUSLCD_SendFanStatusToDisplay ", var.VP); + DEBUG_ECHOLNPAIR(" 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_ECHOPAIR(" DGUSLCD_SendHeaterStatusToDisplay ", var.VP); + DEBUG_ECHOLNPAIR(" 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_ECHOPAIR(" DGUSLCD_SendWaitingStatusToDisplay ", var.VP); + //DEBUG_ECHOLNPAIR(" data ", swap16(index)); + if (period++ > DGUS_UI_WAITING_STATUS_PERIOD) { + dgusdisplay.WriteVariable(var.VP, index); + //DEBUG_ECHOLNPAIR(" 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_ECHOPAIR("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_ECHOPAIR("new topfile adjusted:", top_file); + } + else if (!filelist.isAtRootDir()) { + filelist.upDir(); + top_file = 0; + ForceCompleteUpdate(); + } + + if (old_top != top_file) ForceCompleteUpdate(); + } + + 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()); + ScreenHandler.GotoScreen( + #if ENABLED(DGUS_LCD_UI_ORIGIN) + DGUSLCD_SCREEN_STATUS + #else + DGUSLCD_SCREEN_SDPRINTMANIPULATION + #endif + ); + } + + 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 + if (!ExtUI::isPrintingFromMediaPaused()) ExtUI::pausePrint(); + break; + case 2: // Abort + ScreenHandler.HandleUserConfirmationPopUp(VP_SD_AbortPrintConfirmed, nullptr, PSTR("Abort printing"), filelist.filename(), PSTR("?"), true, true, false, true); + break; + } + } + + 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::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); + DGUSLCD_SendStringToDisplay(var); + } + + void DGUSScreenHandler::SDCardInserted() { + top_file = 0; + filelist.refresh(); + auto cs = ScreenHandler.getCurrentScreen(); + if (cs == DGUSLCD_SCREEN_MAIN || cs == DGUSLCD_SCREEN_STATUS) + ScreenHandler.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 + ) ScreenHandler.GotoScreen(DGUSLCD_SCREEN_MAIN); + } + + void DGUSScreenHandler::SDCardError() { + DGUSScreenHandler::SDCardRemoved(); + ScreenHandler.sendinfoscreen(PSTR("NOTICE"), nullptr, PSTR("SD card error"), nullptr, true, true, true, true); + ScreenHandler.SetupConfirmAction(nullptr); + ScreenHandler.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_ECHOLNPAIR("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::ScreenChangeHook(DGUS_VP_Variable &var, void *val_ptr) { + uint8_t *tmp = (uint8_t*)val_ptr; + + // The keycode in target is coded as <from-frame><to-frame>, 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]; + + 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_ECHOLNPAIR("WARNING: No screen Mapping found for ", target); + #endif +} + +void DGUSScreenHandler::HandleAllHeatersOff(DGUS_VP_Variable &var, void *val_ptr) { + thermalManager.disable_all_heaters(); + ScreenHandler.ForceCompleteUpdate(); // hint to send all data. +} + +void DGUSScreenHandler::HandleTemperatureChanged(DGUS_VP_Variable &var, void *val_ptr) { + uint16_t newvalue = swap16(*(uint16_t*)val_ptr); + uint16_t acceptedvalue; + + switch (var.VP) { + default: return; + #if HOTENDS >= 1 + case VP_T_E0_Set: + thermalManager.setTargetHotend(newvalue, 0); + acceptedvalue = thermalManager.temp_hotend[0].target; + break; + #endif + #if HOTENDS >= 2 + case VP_T_E1_Set: + thermalManager.setTargetHotend(newvalue, 1); + acceptedvalue = thermalManager.temp_hotend[1].target; + break; + #endif + #if HAS_HEATED_BED + case VP_T_Bed_Set: + thermalManager.setTargetBed(newvalue); + acceptedvalue = thermalManager.temp_bed.target; + 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); + ScreenHandler.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 EXTRUDERS + uint16_t newvalue = swap16(*(uint16_t*)val_ptr); + uint8_t target_extruder; + switch (var.VP) { + default: return; + #if HOTENDS >= 1 + case VP_Flowrate_E0: target_extruder = 0; break; + #endif + #if HOTENDS >= 2 + case VP_Flowrate_E1: target_extruder = 1; break; + #endif + } + + planner.set_flow(target_extruder, newvalue); + ScreenHandler.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 HOTENDS >= 1 + case VP_MOVE_E0: target_extruder = ExtUI::extruder_t::E0; break; + #endif + #if HOTENDS >= 2 + case VP_MOVE_E1: target_extruder = ExtUI::extruder_t::E1; break; + #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::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, dont 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_ECHOPAIR(" homing ", axiscode); + char buf[6] = "G28 X"; + buf[4] = axiscode; + //DEBUG_ECHOPAIR(" ", buf); + queue.enqueue_one_now(buf); + //DEBUG_ECHOLNPGM(" ✓"); + ScreenHandler.ForceCompleteUpdate(); + return; + } + else { + //movement + DEBUG_ECHOPAIR(" move ", axiscode); + bool old_relative_mode = relative_mode; + if (!relative_mode) { + //DEBUG_ECHOPGM(" G91"); + queue.enqueue_now_P(PSTR("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_ECHOPAIR(" ", 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_ECHOPAIR(" ", buf); + } + //while (!enqueue_and_echo_command(buf)) idle(); + //DEBUG_ECHOLNPGM(" ✓ "); + if (!old_relative_mode) { + //DEBUG_ECHOPGM("G90"); + queue.enqueue_now_P(PSTR("G90")); + //DEBUG_ECHOPGM(" ✓ "); + } + } + + ScreenHandler.ForceCompleteUpdate(); + DEBUG_ECHOLNPGM("manmv done."); + return; + + cannotmove: + DEBUG_ECHOLNPAIR(" cannot move ", axiscode); + return; +} + +void DGUSScreenHandler::HandleMotorLockUnlock(DGUS_VP_Variable &var, void *val_ptr) { + DEBUG_ECHOLNPGM("HandleMotorLockUnlock"); + + char buf[4]; + const int16_t lock = swap16(*(uint16_t*)val_ptr); + strcpy_P(buf, lock ? PSTR("M18") : PSTR("M17")); + + //DEBUG_ECHOPAIR(" ", buf); + queue.enqueue_one_now(buf); +} + +#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_P(PSTR("M1000")); + ScreenHandler.GotoScreen(DGUSLCD_SCREEN_SDPRINTMANIPULATION); + } + else { + recovery.cancel(); + ScreenHandler.GotoScreen(DGUSLCD_SCREEN_STATUS); + } + } + +#endif + +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()); + queue.inject_P(PSTR("M502\nM500")); + break; + case 2: queue.inject_P(PSTR("M501")); break; + case 3: queue.inject_P(PSTR("M500")); break; + } +} + +void DGUSScreenHandler::HandleStepPerMMChanged(DGUS_VP_Variable &var, void *val_ptr) { + DEBUG_ECHOLNPGM("HandleStepPerMMChanged"); + + uint16_t value_raw = swap16(*(uint16_t*)val_ptr); + DEBUG_ECHOLNPAIR("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_ECHOLNPAIR_F("value:", value); + ExtUI::setAxisSteps_per_mm(value, axis); + DEBUG_ECHOLNPAIR_F("value_set:", ExtUI::getAxisSteps_per_mm(axis)); + ScreenHandler.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_ECHOLNPAIR("value_raw:", value_raw); + float value = (float)value_raw/10; + ExtUI::extruder_t extruder; + switch (var.VP) { + default: return; + #if HOTENDS >= 1 + case VP_E0_STEP_PER_MM: extruder = ExtUI::extruder_t::E0; break; + #endif + #if HOTENDS >= 2 + case VP_E1_STEP_PER_MM: extruder = ExtUI::extruder_t::E1; break; + #endif + } + DEBUG_ECHOLNPAIR_F("value:", value); + ExtUI::setAxisSteps_per_mm(value,extruder); + DEBUG_ECHOLNPAIR_F("value_set:", ExtUI::getAxisSteps_per_mm(extruder)); + ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + return; +} + +#if HAS_PID_HEATING + void DGUSScreenHandler::HandleTemperaturePIDChanged(DGUS_VP_Variable &var, void *val_ptr) { + uint16_t rawvalue = swap16(*(uint16_t*)val_ptr); + DEBUG_ECHOLNPAIR("V1:", rawvalue); + float value = (float)rawvalue / 10; + DEBUG_ECHOLNPAIR("V2:", value); + float newvalue = 0; + + switch (var.VP) { + default: return; + #if HOTENDS >= 1 + 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 HOTENDS >= 2 + 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_ECHOLNPAIR_F("V3:", newvalue); + *(float *)var.memadr = newvalue; + ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + } + + 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 HOTENDS >= 1 + case VP_PID_AUTOTUNE_E0: // Autotune Extruder 0 + sprintf(buf, "M303 E%d C5 S210 U1", ExtUI::extruder_t::E0); + break; + #endif + #if HOTENDS >= 2 + case VP_PID_AUTOTUNE_E1: + sprintf(buf, "M303 E%d C5 S210 U1", ExtUI::extruder_t::E1); + break; + #endif + #endif + #if ENABLED(PIDTEMPBED) + case VP_PID_AUTOTUNE_BED: + sprintf(buf, "M303 E-1 C5 S70 U1"); + break; + #endif + } + + if (buf[0]) queue.enqueue_one_now(buf); + + #if ENABLED(DGUS_UI_WAITING) + sendinfoscreen(PSTR("PID is autotuning"), PSTR("please wait"), NUL_STR, NUL_STR, true, true, true, true); + GotoScreen(DGUSLCD_SCREEN_WAITING); + #endif + } +#endif + +#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); + ScreenHandler.skipVP = var.VP; // don't overwrite value the next update time as the display might autoincrement in parallel + return; + } +#endif + +#if ENABLED(BABYSTEPPING) + void DGUSScreenHandler::HandleLiveAdjustZ(DGUS_VP_Variable &var, void *val_ptr) { + DEBUG_ECHOLNPGM("HandleLiveAdjustZ"); + + int16_t flag = swap16(*(uint16_t*)val_ptr); + int16_t steps = flag ? -20 : 20; + ExtUI::smartAdjustAxis_steps(steps, ExtUI::axis_t::Z, true); + ScreenHandler.ForceCompleteUpdate(); + 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 HOTENDS >= 1 + case VP_E0_CONTROL: + #endif + #if HOTENDS >= 2 + case VP_E1_CONTROL: + #endif + #if HOTENDS >= 3 + case VP_E2_CONTROL: + #endif + preheat_temp = PREHEAT_1_TEMP_HOTEND; + break; + + case VP_BED_CONTROL: + preheat_temp = PREHEAT_1_TEMP_BED; + break; + } + + *(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"); + + uint8_t e_temp = 0; + TERN_(HAS_HEATED_BED, uint8_t bed_temp = 0); + const uint16_t preheat_option = swap16(*(uint16_t*)val_ptr); + switch (preheat_option) { + default: + case 0: // Preheat PLA + #if defined(PREHEAT_1_TEMP_HOTEND) && defined(PREHEAT_1_TEMP_BED) + e_temp = PREHEAT_1_TEMP_HOTEND; + TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_1_TEMP_BED); + #endif + break; + case 1: // Preheat ABS + #if defined(PREHEAT_2_TEMP_HOTEND) && defined(PREHEAT_2_TEMP_BED) + e_temp = PREHEAT_2_TEMP_HOTEND; + TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_2_TEMP_BED); + #endif + break; + case 2: // Preheat PET + #if defined(PREHEAT_3_TEMP_HOTEND) && defined(PREHEAT_3_TEMP_BED) + e_temp = PREHEAT_3_TEMP_HOTEND; + TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_3_TEMP_BED); + #endif + break; + case 3: // Preheat FLEX + #if defined(PREHEAT_4_TEMP_HOTEND) && defined(PREHEAT_4_TEMP_BED) + e_temp = PREHEAT_4_TEMP_HOTEND; + TERN_(HAS_HEATED_BED, bed_temp = PREHEAT_4_TEMP_BED); + #endif + break; + case 7: break; // Custom preheat + case 9: break; // Cool down + } + + switch (var.VP) { + default: return; + #if HOTENDS >= 1 + case VP_E0_BED_PREHEAT: + thermalManager.setTargetHotend(e_temp, 0); + TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(bed_temp)); + break; + #endif + #if HOTENDS >= 2 + case VP_E1_BED_PREHEAT: + thermalManager.setTargetHotend(e_temp, 1); + TERN_(HAS_HEATED_BED, thermalManager.setTargetBed(bed_temp)); + break; + #endif + } + + // Go to the preheat screen to show the heating progress + GotoScreen(DGUSLCD_SCREEN_PREHEAT); + } + +#endif + +#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; + + static filament_data_t filament_data; + + 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 HOTENDS >= 1 + thermalManager.setTargetHotend(e_temp, ExtUI::extruder_t::E0); + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + case VP_E0_FILAMENT_LOAD_UNLOAD: + filament_data.extruder = ExtUI::extruder_t::E0; + thermalManager.setTargetHotend(e_temp, filament_data.extruder); + break; + #endif + #if HOTENDS >= 2 + 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 + +void DGUSScreenHandler::UpdateNewScreen(DGUSLCD_Screens newscreen, bool popup) { + DEBUG_ECHOLNPAIR("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_ECHOLNPAIR("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_ECHOPAIR(" UpdateScreenVPData Screen: ", current_screen); + + const uint16_t *VPList = DGUSLCD_FindScreenVPMapList(current_screen); + if (!VPList) { + DEBUG_ECHOLNPAIR(" 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_ECHOPAIR(" 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_ECHOPAIR(" calling handler for ", rcpy.VP); + sent_one = true; + rcpy.send_to_display_handler(rcpy); + } + else { + //auto x=dgusdisplay.GetFreeTxBuffer(); + //DEBUG_ECHOLNPAIR(" tx almost full: ", x); + //DEBUG_ECHOPAIR(" 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); +} + +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(DGUSLCD_SCREEN_MAIN); + } + #endif + return IsScreenComplete(); +} + +void DGUSDisplay::RequestScreen(DGUSLCD_Screens screen) { + DEBUG_ECHOLNPAIR("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 diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.h b/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.h new file mode 100644 index 0000000..df738db --- /dev/null +++ b/Marlin/src/lcd/extui/lib/dgus/DGUSScreenHandler.h @@ -0,0 +1,232 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "DGUSDisplay.h" +#include "DGUSVPVariable.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 specifing whether the strings are in RAM or FLASH. + static void sendinfoscreen(const char* line1, const char* line2, const char* line3, const char* line4, bool l1inflash, bool l2inflash, bool l3inflash, bool liinflash); + + static void HandleUserConfirmationPopUp(uint16_t ConfirmVP, const char* line1, const char* line2, const char* line3, const char* 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 the Confirm screen. + static void ScreenConfirmedOK(DGUS_VP_Variable &var, void *val_ptr); + + // Update data after went to new screen (by display or by GotoScreen) + // remember: store the last-displayed screen, so it can get returned to. + // (e.g for pop up 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<typename T> + 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<unsigned int decimals> + 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<unsigned int decimals> + 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 inline void ForceCompleteUpdate() { update_ptr = 0; ScreenComplete = false; } + /// Has all VPs sent to the screen + static inline bool IsScreenComplete() { return ScreenComplete; } + + static inline DGUSLCD_Screens getCurrentScreen() { return current_screen; } + + static inline void SetupConfirmAction( void (*f)()) { confirm_action_cb = f; } + +private: + 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)(); +}; + +extern DGUSScreenHandler ScreenHandler; diff --git a/Marlin/src/lcd/extui/lib/dgus/DGUSVPVariable.h b/Marlin/src/lcd/extui/lib/dgus/DGUSVPVariable.h new file mode 100644 index 0000000..8c193c7 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include <stdint.h> + +/** + * 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<typename T> + 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/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.cpp new file mode 100644 index 0000000..467444c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.cpp @@ -0,0 +1,486 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/* 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, VP_E0_STATUS, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_Flowrate_E0, + #endif + #if HOTENDS >= 2 + VP_Flowrate_E1, + #endif + VP_PrintProgress_Percentage, + VP_PrintTime, + 0x0000 +}; + +const uint16_t VPList_Preheat[] PROGMEM = { + #if HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + VP_T_E1_Is, VP_T_E1_Set, + #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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + VP_E0_FILAMENT_LOAD_UNLOAD, + #endif + #if HOTENDS >= 2 + VP_T_E1_Is, VP_T_E1_Set, + VP_E1_FILAMENT_LOAD_UNLOAD, + #endif + 0x0000 +}; + +const uint16_t VPList_Filament_load_unload[] PROGMEM = { + #if HOTENDS >= 1 + VP_E0_FILAMENT_LOAD_UNLOAD, + #endif + #if HOTENDS >= 2 + VP_E1_FILAMENT_LOAD_UNLOAD, + #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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, VP_Flowrate_E0, + #endif + #if HOTENDS >= 2 + VP_T_E1_Is, VP_T_E1_Set, VP_Flowrate_E1, + #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 HOTENDS >= 1 + VP_E0_STEP_PER_MM, + #endif + #if HOTENDS >= 2 + VP_E1_STEP_PER_MM, + #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 HOTENDS >= 1 + 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 HOTENDS >= 1 + VP_SD_Print_ProbeOffsetZ, + #endif + 0x0000 +}; + +const uint16_t VPList_Z_Offset[] PROGMEM = { + #if HOTENDS >= 1 + 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; + +// 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 sizeo of the var cannot be determined automaticalyl (eg. 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 } + +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 HOTENDS >= 1 + 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 HOTENDS >= 2 + 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(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_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<int16_t>, &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 HOTENDS >= 1 + VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>), + #endif + #if HOTENDS >= 2 + VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>), + #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 cant 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/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.h b/Marlin/src/lcd/extui/lib/dgus/fysetc/DGUSDisplayDef.h new file mode 100644 index 0000000..910f5f7 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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 <https://www.gnu.org/licenses/>. + * + */ +#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" + DGUSLDC_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; + +// Wating 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/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.cpp new file mode 100644 index 0000000..536640e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.cpp @@ -0,0 +1,485 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/* 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, VP_E0_STATUS, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_Flowrate_E0, + #endif + #if HOTENDS >= 2 + VP_Flowrate_E1, + #endif + VP_PrintProgress_Percentage, + VP_PrintTime, + 0x0000 +}; + +const uint16_t VPList_Preheat[] PROGMEM = { + #if HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + VP_T_E1_Is, VP_T_E1_Set, + #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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + VP_E0_FILAMENT_LOAD_UNLOAD, + #endif + #if HOTENDS >= 2 + VP_T_E1_Is, VP_T_E1_Set, + #endif + 0x0000 +}; + +const uint16_t VPList_Filament_load_unload[] PROGMEM = { + #if HOTENDS >= 1 + VP_E0_FILAMENT_LOAD_UNLOAD, + #endif + #if HOTENDS >= 2 + VP_E1_FILAMENT_LOAD_UNLOAD, + #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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + VP_T_E1_Is, VP_T_E1_Set, + #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, + #if HOTENDS >= 1 + VP_E0_STEP_PER_MM, + #endif + #if HOTENDS >= 2 + VP_E1_STEP_PER_MM, + #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 HOTENDS >= 1 + 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 HOTENDS >= 1 + VP_SD_Print_ProbeOffsetZ, + #endif + 0x0000 +}; + +const uint16_t VPList_Z_Offset[] PROGMEM = { + #if HOTENDS >= 1 + 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; + +// 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 sizeo of the var cannot be determined automaticalyl (eg. 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 } + +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 HOTENDS >= 1 + 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 HOTENDS >= 2 + VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, 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_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(PIDTEMP) + 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<int16_t>, &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 HOTENDS >= 1 + VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>), + #endif + #if HOTENDS >= 2 + VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>), + #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 cant 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/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.h b/Marlin/src/lcd/extui/lib/dgus/hiprecy/DGUSDisplayDef.h new file mode 100644 index 0000000..d18989a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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 <https://www.gnu.org/licenses/>. + * + */ +#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" + DGUSLDC_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; + +// Wating 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/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.cpp b/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.cpp new file mode 100644 index 0000000..28e66e5 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.cpp @@ -0,0 +1,310 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/* DGUS implementation written by coldtobi in 2019 for Marlin */ + +#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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_T_E0_Is, VP_T_E0_Set, + #endif + #if HOTENDS >= 2 + 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 HOTENDS >= 1 + VP_Flowrate_E0, + #endif + #if HOTENDS >= 2 + VP_Flowrate_E1, + #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; + +// 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 sizeo of the var cannot be determined automaticalyl (eg. 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 } + +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 HOTENDS >= 1 + VPHELPER(VP_T_E0_Is, nullptr, nullptr, SET_VARIABLE(getActualTemp_celsius, E0, long)), + VPHELPER(VP_T_E0_Set, nullptr, GET_VARIABLE(setTargetTemp_celsius, E0), + SET_VARIABLE(getTargetTemp_celsius, E0)), + 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 HOTENDS >= 2 + VPHELPER(VP_T_E1_Is, &thermalManager.temp_hotend[1].celsius, nullptr, 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<int16_t>, &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 HOTENDS >= 1 + VPHELPER(VP_E0_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(0)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>), + #endif + #if HOTENDS >= 2 + VPHELPER(VP_E1_STEP_PER_MM, &planner.settings.axis_steps_per_mm[E_AXIS_N(1)], ScreenHandler.HandleStepPerMMExtruderChanged, ScreenHandler.DGUSLCD_SendFloatAsIntValueToDisplay<1>), + #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 cant 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/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.h b/Marlin/src/lcd/extui/lib/dgus/origin/DGUSDisplayDef.h new file mode 100644 index 0000000..5c5a315 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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 <https://www.gnu.org/licenses/>. + * + */ +#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" + DGUSLDC_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; + +// Wating 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp new file mode 100644 index 0000000..a64c237 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.cpp @@ -0,0 +1,553 @@ +/********************* + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../compat.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<ram_write>(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_START(); SERIAL_ECHOLNPAIR(" Manufacturer ID, got: ", manufacturer_id); + SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(" Device Type , got: ", device_type); + SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(" 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 preceeded + * with a 32-bit delimiter 'LULZ', so that we can distinguish written and + * unwritten data: + * + * 'LULZ' <--- 1st record delimiter + * <data_byte> + * <data_byte> + * <data_byte> + * 'LULZ' <--- 2nd record delimiter + * <data_byte> + * <data_byte> + * <data_byte> + * ... + * 'LULZ' <--- Last record delimiter + * <data_byte> + * <data_byte> + * <data_byte> + * 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_START(); SERIAL_ECHOLNPAIR("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_ECHOPAIR("Writing UI settings to SPI Flash (offset ", write_addr); + SERIAL_ECHOPGM(")..."); + + 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<ram_write>(&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(progmem_str filename, uint8_t slot) { + #if ENABLED(SDSUPPORT) + uint32_t addr; + uint8_t buff[write_page_size]; + + strcpy_P( (char*) buff, (const char*) 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_START(); SERIAL_ECHOLNPAIR("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<UIFlashStorage::BootMediaReader*>(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(progmem_str, 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/flash_storage.h new file mode 100644 index 0000000..eef8cf8 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +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 (progmem_str 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp new file mode 100644 index 0000000..9868492 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.cpp @@ -0,0 +1,63 @@ +/************************ + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../compat.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + #include "media_file_reader.h" + + #if ENABLED(SDSUPPORT) + bool MediaFileReader::open(const char* filename) { + card.init(SD_SPI_SPEED, SDSS); + volume.init(&card); + root.openRoot(&volume); + 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<MediaFileReader*>(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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h new file mode 100644 index 0000000..be393a9 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/archim2-flash/media_file_reader.h @@ -0,0 +1,48 @@ +/********************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +#include "../../../../../inc/MarlinConfigPre.h" + +#if ENABLED(SDSUPPORT) + #include "../../../../../sd/SdFile.h" + #include "../../../../../sd/cardreader.h" +#endif + +class MediaFileReader { + private: + #if ENABLED(SDSUPPORT) + Sd2Card card; + SdVolume volume; + 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/compat.h new file mode 100644 index 0000000..c01d45e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 inline uint32_t safe_millis() { return millis(); } + static inline void yield() {} + }; +#endif + +class __FlashStringHelper; +typedef const __FlashStringHelper *progmem_str; +extern const char G28_STR[]; diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/config.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/config.h new file mode 100644 index 0000000..76b2315 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/config.h @@ -0,0 +1,26 @@ +/************ + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +#include "compat.h" + +// Configure this display with options in Configuration_adv.h diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/LICENSE.txt new file mode 100644 index 0000000..e600086 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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. <https://fsf.org/> + 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. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + +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: + + <program> Copyright (C) <year> <name of author> + 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 +<https://www.gnu.org/licenses/>. + + 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 +<https://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/README.md b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/README.md new file mode 100644 index 0000000..6ba985d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h new file mode 100644 index 0000000..6bb9208 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/boards.h @@ -0,0 +1,184 @@ +/************ + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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_ALEPHOBJECTS_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 */ + } +#else + + #error "Unknown or no TOUCH_UI_FTDI_EVE board specified. To add a new board, modify this file." + +#endif diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp new file mode 100644 index 0000000..1db1175 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.cpp @@ -0,0 +1,1194 @@ +/**************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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(progmem_str 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<ram_write>(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, progmem_str str, uint16_t len, uint8_t padding) { + spi_ftdi_select(); + spi_write_addr(reg_address); + spi_write_bulk<pgm_write>(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<pgm_write>(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, progmem_str data, uint16_t len, uint8_t padding) { + spi_ftdi_select(); + spi_write_addr(reg_address); + spi_write_bulk<xbm_write>(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 <class T> 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 <class T> bool CLCD::CommandFifo::write(T data, uint16_t len) { + const uint8_t padding = MULTIPLE_OF_4(len) - len; + + uint8_t pad_bytes[] = {0, 0, 0, 0}; + return _write_unaligned(data, len) && + _write_unaligned(pad_bytes, padding); +} +#else +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 <class T> 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_START(); + SERIAL_ECHOPAIR("Waiting for ", len + padding); + SERIAL_ECHOLNPAIR(" 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 + +template bool CLCD::CommandFifo::write(const void*, uint16_t); +template bool CLCD::CommandFifo::write(progmem_str, uint16_t); + +// CO_PROCESSOR COMMANDS + +void CLCD::CommandFifo::str(const char * data) { + write(data, strlen(data)+1); +} + +void CLCD::CommandFifo::str(progmem_str 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 apropriate 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 "); + #endif + break; + } + else + delay(1); + + if (counter == 249) { + #if ENABLED(TOUCH_UI_DEBUG) + SERIAL_ECHO_START(); + SERIAL_ECHOLNPAIR("Timeout waiting for device ID, should be 124, got ", device_id); + #endif + } + } + + /* make sure that all units are in working conditions, 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 "); + #endif + break; + } + else + delay(1); + + if (ENABLED(TOUCH_UI_DEBUG) && counter == 99) { + SERIAL_ECHO_START(); + SERIAL_ECHOLNPAIR("Timeout waiting for reset status. Should be 0x00, got ", reset_status); + } + } + + 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 ANY(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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h new file mode 100644 index 0000000..376beae --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/commands.h @@ -0,0 +1,262 @@ +/**************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + + /**************************************************************************** + * 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 Primative * + * 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 *progmem_str; + +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, progmem_str str, uint16_t len, uint8_t padding = 0); + static void mem_write_xbm (uint32_t reg_address, progmem_str 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(progmem_str 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 <class T> bool _write_unaligned(T data, uint16_t len); + #endif + void start(); + + public: + template <class T> 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); + void str (progmem_str 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h new file mode 100644 index 0000000..507e251 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/constants.h @@ -0,0 +1,414 @@ +/*************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/**************************************************************************** + * 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 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/display_list.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/display_list.h new file mode 100644 index 0000000..99a9e0e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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;} + 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;} + /* 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/ftdi_basic.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/ftdi_basic.h new file mode 100644 index 0000000..47cd698 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft800.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft800.h new file mode 100644 index 0000000..2605370 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/**************************************************************************** + * 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft810.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/registers_ft810.h new file mode 100644 index 0000000..e57d11c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/**************************************************************************** + * 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h new file mode 100644 index 0000000..5b29816 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/resolutions.h @@ -0,0 +1,127 @@ +/***************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 { + 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; + } + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.cpp new file mode 100644 index 0000000..006cbe8 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/basic/spi.h new file mode 100644 index 0000000..e3a23d7 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +#ifndef CLCD_USE_SOFT_SPI + #include <SPI.h> +#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<bulk_write_op byte_op> + 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<bulk_write_op byte_op> + 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h new file mode 100644 index 0000000..9be7882 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/compat.h @@ -0,0 +1,278 @@ +/**************************************************************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 <Arduino.h> + + #ifndef CLCD_USE_SOFT_SPI + #include <SPI.h> + #endif + + namespace fast_io { + + template<typename port_t,uint8_t bits> + struct port_pin { + typedef port_t port; + static inline void set_high() {port::port() = (port::port() | bits);} + static inline void set_low() {port::port() = (port::port() & (~bits));} + static inline void set_input() {port::ddr() = (port::ddr() & (~bits));} + static inline void set_input_pullup() {set_input(); set_high();} + static inline void set_output() {port::ddr() = (port::ddr() | bits);} + static inline uint8_t read() {return port::pin() & bits;} + static inline 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<port_##ID, 0b00000001> AVR_##ID##0; \ + typedef port_pin<port_##ID, 0b00000010> AVR_##ID##1; \ + typedef port_pin<port_##ID, 0b00000100> AVR_##ID##2; \ + typedef port_pin<port_##ID, 0b00001000> AVR_##ID##3; \ + typedef port_pin<port_##ID, 0b00010000> AVR_##ID##4; \ + typedef port_pin<port_##ID, 0b00100000> AVR_##ID##5; \ + typedef port_pin<port_##ID, 0b01000000> AVR_##ID##6; \ + typedef port_pin<port_##ID, 0b10000000> 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<uint8_t p> + struct arduino_digital_pin { + static constexpr uint8_t pin = p; + static inline void set_high() {digitalWrite(p, HIGH);} + static inline void set_low() {digitalWrite(p, LOW);} + static inline void set_input() {pinMode(p, INPUT);} + static inline void set_input_pullup() {pinMode(p, INPUT_PULLUP);} + static inline void set_output() {pinMode(p, OUTPUT);} + static inline uint8_t read() {return digitalRead(p);} + static inline void write(bool v) {digitalWrite(p, v ? HIGH : LOW);} + }; + + #define MAKE_ARDUINO_PINS(ID) typedef arduino_digital_pin<ID> 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 + + #define SERIAL_ECHO_START() + #define SERIAL_ECHOLNPGM(str) Serial.println(F(str)) + #define SERIAL_ECHOPGM(str) Serial.print(F(str)) + #define SERIAL_ECHO_MSG(str) Serial.println(str) + #define SERIAL_ECHOLNPAIR(str, val) do{ Serial.print(F(str)); Serial.println(val); }while(0) + #define SERIAL_ECHOPAIR(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)) // NOT('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_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 '<nul>' + #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 + #if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC) + #define UNUSED(X) (void)X + #else + #define UNUSED(x) ((void)(x)) + #endif + #endif + +#endif // !__MARLIN_FIRMWARE__ diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/bitmap_info.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/bitmap_info.h new file mode 100644 index 0000000..7326070 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp new file mode 100644 index 0000000..e324cb9 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.cpp @@ -0,0 +1,29 @@ +/************************* + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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; + +#endif // FTDI_EXTENDED diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h new file mode 100644 index 0000000..da51ee6 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/command_processor.h @@ -0,0 +1,437 @@ +/*********************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 cannonical 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; + } + + // 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; + } + + template<typename T> + 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; + //const int16_t outer_bar_r = widget_h / 2; + //const int16_t knob_r = outer_bar_r - 1.5; + // 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 + h / 2, y + (h - widget_h) / 2 + fudge_y, w - h, _font, options, state); + CLCD::CommandFifo::str(text); + return *this; + } + + CommandProcessor& toggle2(int16_t x, int16_t y, int16_t w, int16_t h, progmem_str no, progmem_str yes, bool state, uint16_t options = FTDI::OPT_3D) { + char text[strlen_P((const char *)no) + strlen_P((const char *)yes) + 2]; + strcpy_P(text, (const char *)no); + strcat(text, "\xFF"); + strcat_P(text, (const char *)yes); + return toggle(x, y, w, h, text, state, options); + } + + // Contrained 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<typename T> + 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<typename T> + 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<typename T> + 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<typename T> + 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<typename T> + 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp new file mode 100644 index 0000000..a13c362 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.cpp @@ -0,0 +1,180 @@ +/**************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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_START(); + SERIAL_ECHOPAIR ("Not enough space in GRAM to cache display list, free space: ", dl_slot_size); + SERIAL_ECHOLNPAIR(" Required: ", dl_size); + #endif + dl_slot_used = 0; + save_slot(); + return false; + } + else { + #if ENABLED(TOUCH_UI_DEBUG) + SERIAL_ECHO_START(); + SERIAL_ECHOPAIR ("Saving DL to RAMG cache, bytes: ", dl_slot_used); + SERIAL_ECHOLNPAIR(" 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_START(); + SERIAL_ECHOPAIR ("Appending to DL from RAMG cache, bytes: ", dl_slot_used); + SERIAL_ECHOLNPAIR(" REG_CMD_DL: ", CLCD::mem_read_32(REG::CMD_DL)); + #endif +} + +#endif // FTDI_EXTENDED diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/dl_cache.h new file mode 100644 index 0000000..73b4b0b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp new file mode 100644 index 0000000..6c0392c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.cpp @@ -0,0 +1,228 @@ +/****************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 supress 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_START(); + SERIAL_ECHOLNPAIR("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_START(); + SERIAL_ECHOLNPAIR("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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/event_loop.h new file mode 100644 index 0000000..c5f0829 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h new file mode 100644 index 0000000..fd84c79 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/ftdi_extended.h @@ -0,0 +1,52 @@ +/******************* + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 "text_box.h" + #include "text_ellipsis.h" +#endif diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h new file mode 100644 index 0000000..82bb8ab --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/grid_layout.h @@ -0,0 +1,98 @@ +/***************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 + +// EDGE_R adds some black space on the right edge of the display +// This shifts some of the screens left to visually center them. + +#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)/GRID_COLS) +#define GRID_Y(y) ((y)*FTDI::display_height/GRID_ROWS) + +// 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) (GRID_X((x)-1) + MARGIN_L) +#define BTN_Y(y) (GRID_Y((y)-1) + MARGIN_T) +#define BTN_W(w) (GRID_X(w) - MARGIN_L - MARGIN_R) +#define BTN_H(h) (GRID_Y(h) - MARGIN_T - MARGIN_B) + +// Abbreviations for common phrases, to allow a 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) + +// 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)); \ + } + +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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/polygon.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/polygon.h new file mode 100644 index 0000000..6aa52f0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 "Applicaton 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/rgb_t.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/rgb_t.h new file mode 100644 index 0000000..62762ee --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp new file mode 100644 index 0000000..944237b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.cpp @@ -0,0 +1,105 @@ +/****************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 < functionTableSize; type++) { + if (GET_METHOD(type, onRedraw) == onRedraw_ptr) { + return type; + } + } + #if ENABLED(TOUCH_UI_DEBUG) + SERIAL_ECHO_START(); + SERIAL_ECHOPAIR("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_START(); + SERIAL_ECHOLNPAIR("New screen: ", type); + #endif + } +} + +void ScreenRef::initializeAll() { + for (uint8_t type = 0; type < functionTableSize; 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h new file mode 100644 index 0000000..1581cbb --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/screen_types.h @@ -0,0 +1,241 @@ +/******************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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<method##_func_t*>(pgm_read_ptr_far(&functionTable[type].method##_ptr)) +#define SCREEN_TABLE PROGMEM const ScreenRef::table_t ScreenRef::functionTable[] = +#define SCREEN_TABLE_POST const uint8_t ScreenRef::functionTableSize = sizeof(ScreenRef::functionTable)/sizeof(ScreenRef::functionTable[0]); + +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[]; + static const uint8_t functionTableSize; + + public: + 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 UNCHACHED 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<uint8_t DL_SLOT,uint32_t DL_SIZE = 0> +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_ECHOLNPAIR("Time to draw screen (ms): ", millis() - start_time); + #endif + } +}; diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_list.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_list.h new file mode 100644 index 0000000..20df15a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 inline const char* name(uint8_t val) { + return (const char* ) pgm_read_ptr_far(&list[val].name); + } + static inline FTDI::SoundPlayer::sound_t* data(uint8_t val) { + return (FTDI::SoundPlayer::sound_t*) pgm_read_ptr_far(&list[val].data); + } +}; diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp new file mode 100644 index 0000000..07d1ff5 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.cpp @@ -0,0 +1,110 @@ +/******************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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_START(); + SERIAL_ECHOPAIR ("Playing note ", int(note)); + SERIAL_ECHOLNPAIR(", instrument ", int(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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/sound_player.h new file mode 100644 index 0000000..fcfe70b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp new file mode 100644 index 0000000..b7422a0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.cpp @@ -0,0 +1,129 @@ +/**************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "ftdi_extended.h" + +#if ENABLED(FTDI_EXTENDED) + +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 &fm, uint16_t w, const char *str, const char *&end) { + w -= fm.get_char_width(' '); + const char *p = str; + end = str; + uint16_t lw = 0, result = 0; + for (;;) { + utf8_char_t c = get_utf8_char_and_inc(p); + if (c == ' ' || c == '\n' || c == '\0') { + if (lw < w || end == str) { + end = (c == '\0') ? p-1 : p; + result = lw; + } + if (c == '\0' || c == '\n') break; + } + lw += fm.get_char_width(c); + } + if (end == str) { + end = p-1; + result = lw; + } + return result; + } + + /** + * This function returns a measurements of the word-wrapped text box. + */ + static void measure_text_box(const FontMetrics &fm, const char *str, uint16_t &width, uint16_t &height) { + const char *line_start = (const char*)str; + const char *line_end; + const uint16_t wrap_width = width; + width = height = 0; + for (;;) { + uint16_t line_width = find_line_break(fm, wrap_width, line_start, line_end); + if (line_end == line_start) break; + width = max(width, line_width); + height += fm.get_height(); + 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) { + uint16_t box_width, box_height; + + FontMetrics fm(font); + + // Shrink the font until we find a font that fits + for (;;) { + box_width = w; + measure_text_box(fm, str, box_width, box_height); + if (box_width <= (uint16_t)w && box_height <= (uint16_t)h) break; + fm.load(--font); + if (font == 26) break; + } + + const uint16_t dx = (options & OPT_RIGHTX) ? w : (options & OPT_CENTERX) ? w/2 : 0; + const uint16_t dy = (options & OPT_CENTERY) ? (h - box_height)/2 : 0; + + const char *line_start = str; + const char *line_end; + for (;;) { + find_line_break(fm, w, line_start, line_end); + if (line_end == line_start) break; + + const size_t line_len = line_end - line_start; + if (line_len) { + char line[line_len + 1]; + strncpy(line, line_start, line_len); + line[line_len] = 0; + if (line[line_len - 1] == '\n' || line[line_len - 1] == ' ') + line[line_len - 1] = 0; + + #if ENABLED(TOUCH_UI_USE_UTF8) + if (has_utf8_chars(line)) { + draw_utf8_text(cmd, x + dx, y + dy, line, fm.fs, options & ~OPT_CENTERY); + } else + #endif + { + cmd.CLCD::CommandFifo::text(x + dx, y + dy, font, options & ~OPT_CENTERY); + cmd.CLCD::CommandFifo::str(line); + } + } + y += fm.get_height(); + + line_start = line_end; + } + } + + void draw_text_box(CommandProcessor& cmd, int x, int y, int w, int h, progmem_str pstr, uint16_t options, uint8_t font) { + char str[strlen_P((const char*)pstr) + 1]; + strcpy_P(str, (const char*)pstr); + draw_text_box(cmd, x, y, w, h, (const char*) str, options, font); + } +} // namespace FTDI + +#endif // FTDI_EXTENDED diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h new file mode 100644 index 0000000..9d8cd44 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_box.h @@ -0,0 +1,30 @@ +/************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +/** + * This function draws text inside a bounding box, doing word wrapping and using the largest font that will fit. + */ +namespace FTDI { + void draw_text_box(class CommandProcessor& cmd, int x, int y, int w, int h, progmem_str 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp new file mode 100644 index 0000000..5fc89f1 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.cpp @@ -0,0 +1,91 @@ +/********************* + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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) { + FontMetrics fm(font); + const int16_t ellipsisWidth = 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; + #ifdef TOUCH_UI_USE_UTF8 + char *tstr = str; + while (*tstr) { + breakPoint = tstr; + const utf8_char_t c = get_utf8_char_and_inc(tstr); + lineWidth += fm.get_char_width(c); + if (lineWidth + ellipsisWidth < w) + break; + } + #else + for (char* c = str; *c; c++) { + lineWidth += fm.get_char_width(*c); + if (lineWidth + ellipsisWidth < w) + breakPoint = c; + } + #endif + + if (lineWidth > w) { + *breakPoint = '\0'; + strcpy_P(breakPoint,PSTR("...")); + } + + cmd.apply_text_alignment(x, y, w, h, options); + #if ENABLED(TOUCH_UI_USE_UTF8) + if (has_utf8_chars(str)) { + draw_utf8_text(cmd, x, y, str, font_size_t::from_romfont(font), options); + } else + #endif + { + 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, progmem_str pstr, uint16_t options, uint8_t font) { + char tmp[strlen_P((const char*)pstr) + 3]; + strcpy_P(tmp, (const char*)pstr); + _draw_text_with_ellipsis(cmd, x, y, w, h, tmp, options, font); + } +} // namespace FTDI + +#endif // FTDI_EXTENDED diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/text_ellipsis.h new file mode 100644 index 0000000..a2d8aa9 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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, progmem_str 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.cpp new file mode 100644 index 0000000..5219c0d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/tiny_timer.h new file mode 100644 index 0000000..f64d033 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 rougly 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/README.txt b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/README.txt new file mode 100644 index 0000000..818bf08 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.cpp new file mode 100644 index 0000000..1c193ad --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set.h new file mode 100644 index 0000000..63493b8 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set_bitmap_31.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/cyrillic_char_set_bitmap_31.h new file mode 100644 index 0000000..00bfe37 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.cpp new file mode 100644 index 0000000..d9acb4f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps.h new file mode 100644 index 0000000..2b0a533 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.png b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.png Binary files differnew file mode 100644 index 0000000..bc46ebe --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.png diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg new file mode 100644 index 0000000..25893f5 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/cyrillic_char_set_bitmap_31.svg @@ -0,0 +1,535 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="40" + height="3234" + viewBox="0 0 10.583333 855.66248" + version="1.1" + id="svg8" + inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)" + sodipodi:docname="cyrillic_char_set_bitmap_31.svg" + inkscape:export-filename="C:\Users\kiril\Documents\PlatformIO\Marlin\Marlin\src\lcd\extui\lib\ftdi_eve_touch_ui\ftdi_eve_lib\extended\unicode\font_bitmaps\cyrillic_char_set_bitmap_31.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="1.4142136" + inkscape:cx="376.00796" + inkscape:cy="-222.93717" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="true" + units="px" + inkscape:window-width="1920" + inkscape:window-height="1021" + inkscape:window-x="-7" + inkscape:window-y="-7" + inkscape:window-maximized="1" + inkscape:document-rotation="0" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:snap-nodes="false" + inkscape:snap-others="false" + showguides="false"> + <inkscape:grid + type="xygrid" + id="grid94" + spacingx="11.1125" + spacingy="12.964583" + originx="3.0055911e-10" + originy="0" /> + <inkscape:grid + type="xygrid" + id="grid110" + snapvisiblegridlinesonly="false" + spacingx="52.916666" + spacingy="12.964583" + color="#ff6400" + opacity="1" + originx="3.0055911e-10" + originy="-2.6458333" + empcolor="#ff6400" + empopacity="1" /> + <inkscape:grid + type="xygrid" + id="grid112" + snapvisiblegridlinesonly="true" + enabled="true" + originx="3.0055911e-10" + spacingx="52.916665" + spacingy="12.964583" + color="#ff6400" + opacity="1" + empcolor="#ff6400" + empopacity="1" + originy="2.3812499" /> + </sodipodi:namedview> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,264.81684)"> + <image + y="-947.59998" + x="-1.7763568e-15" + id="image4606" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAABJgCAYAAACFiF0FAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnetu6zrSKJnBev9X9vlxPgWOI6l4aZKt7CpgMNgriVUmdSOb3fx6vV6vkoj/7Rb4RCFCIUIh QiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiHi3/t/fH19 /fjhjkUP6VpIIUIhQiFCIUIhQiFCIUIhQiHixzt1hoXD6VpIIUIhwpEroRDhnZpQiFCIUIhQiFCI UIhQiFCISCdUNQxaOTxK10IKEQoRzxG6urRnj26f00K7OBXa1V2llPJlVQtAIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiFCIUIhQiFCIUIhQiHiH//K/+c9iHc2cUs/ryVdCz1TaFV3VQutRCEindCPaNDn goEIWk/ydC2UTgiXL6+8B5WSsIWqhejbR0VKb4XoqptxVT63y1aRTujr9Xq9MtyhD9K1UDqhf6Xk uEMfpGuhZwjt6q5LoZ0oRChEuAaNUIhQiFCIUIhQiEgnVB1aOJj5+lpKwhZSiEgnVHVSX82OzDjB cUqvdqomakrnUqjnABFSp1129sE0pH7/t+khzpWpOb+EWpu9tuW6hWoO2PM7taS7D6UTan7aX7Hk xljKnHjGHb+Eoq+aVqrPoVVSTTmKLc+2Xm7nh2oOvnQWtuZg0a1WdaeuFYuga0rv7uBbVsfctdpo Sw09OlKOy5a/ftQQ2VJWGyRyC3120eox2S+hqINNHwbdDaWjn/6nj46Rg0x5dPR+aMRt4vIl/6rU zywRFDo72Oz5xVKy34cykE6oaeS64mGbroUUIhQiFCIUIhQiFCLSCQ2Fp2ZQHQ1aMQP7S6jmgLOl cBh0JjIaNbzju4VoiNMiMNK94VfZ1knPTyLOr2n3oe1pFOGZwFdj+OgDEpeXfcv5MC3xtickPj0D 724Vw4rn2WmX1R54+XKd1TKlPOV9iLhrndF3qbB1jHe3ieNnNWIhXRYZgmhqoZoTeTSg17Wyobar 6HOGhGqIWBoWUkQikqbwlLOwn7S2zvRX2EPiToZEP0cg9PtN0aAaUow6aqVrfi98ld7yhythMZvZ KEQoRChEKEQoRChEKEQoRAylBM4YyQ7NU88IUw13WXSksSvmOjOqWBVz/eyWmflD3Rl4LqzcRUho oZSJsY6amfmlVxkxexnG0KMjWqaUgRXnswJ6l102Mq84Qmh6ewS/zqFdIgdd6e0UG3v/XyvfLdR6 Oc9aslN9Uq/KEP5fywe3SvW0YPN9aHZLdWdxfhL1Ktv9tJ9VazhnWmlv5t3Z3179W5PQGbXjsuhL /3SF1d0Bj/+uWcnQw9Qq8D1dF5ISeDeIbJW6XdDUeheOaGFLaBIKEQoRChEKEQoRChEKEQoR6YSs rkMoRChEdM3kz+Q5LbSL0PpDEaRrIdwDbzXpWkghQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFC IUIhIp1QeDGbUbqK2cykuXZMKZvW5F9hMZsrmVVUd9m2qqcHu9IpToV2RqfT3am7cxRnUZXFuZLn ddlqqmpYreSH0O7zp5SnddkOFCIUIhQiFCJ+CKVfjJJ61LEKhQgsIrGaprH9CvJ3WSljibijPKOF StnXSrmHQcTyTWjOWN114WU2Rkk3pefGjoRChEJEU+2YFXyVUr6v5d1vi6VknNLb+TJ2xnCplmhu K6PsIHd4KkPX5bwxvrO7lfK3UCkPyC9z5JqJ56SVXhXTms1zWmgXChEKEQoRChHPEdq1Du05LbSL ZwptX8eYYrIhC7iOcfvCynfSh6dWcDnHuP0lf/fc4sHpPHWqyYbdc435Js5rNpFdyek89U5y34cy oBChEKEQoRChEKEQkU4IV1ilynPdgULEZfVl2pmr5veGha4Oevdv0QwPpaMlv1uodXvUWbeA5l1x thUAuGqlLauFU2eTr9r77qA6eXvVMp7LnZWutiWctV0hCu0i3bNMIUIhQiFCIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiEinVB1AYBVE6HpWkghQiFCISKd0PeNsTV2Qb/fe+NM10LphE5jrmf4LMuCQoRC hEJEOqHqUYdJk1lQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiLhc +7G9UlwWFCIUIk6FUlUb3E1+od3Z7tVLvlaRv8t2oxChEKEQoRChEKEQoRChEKEQoRChEKEQoRCR TuiyLmwNM2ZM0rVQOqEfXZZh0ipdCylEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQo RChEKEQoRChEKEQoRChEKEQoRNwutdgRx0/XQgoRrv0gFCIUIhQiFCIUIhQiFCIUItIJVRfuf+d9 uBT92tvcQq3L5FsZ6rLta/Jnt04pAy3kNj2frOiuUjpbaOYI95ldtqq7SuloodkTEii0snVKaWyh FdM1zzqpV3dXKQ0t5L5Bn+zorlIqW2jlZOip0K7WKaWihVZPFec/qXd2VynQQkaDyofQ7u4q5aaF ttf0zNA6pVy0kPUY3/hfKXm6q5STFtodVUzXZf9K2d8q76RrIYUIhQiFCIUIhQiFCIWIqgDe1Svu jPeoS6Ga9+zjdyLFQuaHIgcJ1bMfr9fr+38zpaomrD4lrsQipG4nG+jc2B5zXcHlZEPtt//8vdFu y9tCWVCIUIhQiFCIUIhQiMgr1PteE50ClreFSmlvpRkxEhy5ng0GZ45kv14nn9LzzaNGICEBvMjh 0GWXHQdZOdFwKzT7wFfkvuwzoBChEKEQoRChEKEQoRDxbKHjdXbmErFfr7A7xmLv5O6yDKv1fg2l j1HG5/9vETrYKZX7HMqAQoRChEKEQoRChEKEQoRChEKEQoRCRDqh6vpDFgDIgkKEQoRChEKEQoRC hEKEQsRQBl4p8a+2t0I7svDCalhFBf9OW+jsw2vWyX59fcWvFq6ROf5tS8Jb60FD88t6FmtvL1Q7 m3RCf297jP9WkkAGhoRmbOvTLTRrj6EuoZmraJqFap91vXQt+ZolU8rgSb01vX3VRllVQqmqL684 b965FVotU0rjS/626su7ZEqpPKlXvifd7oG3g+Gh9BW9rfq33odm8Pde8qNRiFCIUIhQiFCIUIhQ iFCISCf0nBKadyJnP586x/j19bUtgFcVLztYUUazuxDJVeWU0ajicNLk0knP7Vus7MrcfOdXC+2W Snen/lsBvC1FtWoPvDU89cm2aNAVPc++y886KzvWIvLJ1pN6Rkno4S5LFcA7iKzA/Pfu1NFcvjGm 2Edxt0wpHRHF2dxWrKwl8onfFQRu+XkrTRUrV5TRPH39eL1elwsnZ3PZZT1lNCMeI7cvaKsqnVYL zTzwFfkfHbtRiFCIUIhQiFCIUIhQiFCIqH6FfWfmStB0LRSyJj+SZ7fQ1pHrJ6umZp7ZZasyFkrp mB/atiZ/F01zjNuSBM7YPvuRYp76YEdXHeQ/qXe2TinZl1pkSDT5FtrdVQfpTuqv1+v1mtFVpuLM 4l8pfc2bKjV5JgoRChHphLpmP0rZnLy9EoUIhQiFCIUIhQiFCIUIhYh0QtX1GGuxMNtsqkYdTgtn Iv889e76MU1ppStIdw5VTzasKrSFQnddGF3ouJSE+WXdC7xnnfwYDbpaaz8jt+yX0OdB6NxYclKP HiQ0m7yHlBl4kShEmIFHhKe3jxKeEhg6Lmt9HMzo2q41aFdP94ibZFNK4B1Tg8Ct2XSRj4+qDLw0 5X5mHviK/I+O3ShEKEQoRChEKEQoRChEKEQ0rUG7GvpEbKT2fQwqqtUyJJq+b9D26jrv3I1MqZTm CNUj1+2pOO9sHZelC+Dt5ja0sD3zJQPDd+pSNsTLKB4WeQMd3j7183enFNU6Y0sAr1bm+LflBSJr nlePCE9tLxCZLkweiUJEbqFVN787wtZ+vLO1YmU0w0u+lpTQvDvQ7AhRczrX7K3lb0to7gjiVe+1 kGYN2syDn5H7Tp0BhQiFCIUIhQiFCIUIhQiFiO9X2OjxleV+ZvHdZSOjisjuntJCW7MWUm8XNj0q vYNuoVQ1rGZGHp/fZbPjskMtNGOKpkkodW1hS0btoivRZGux49UoRDRHg6xPvRuFCIUIhYju3dtn ka6FFCIUIhQiFCIUIhQiFCIUItIJVa1Bm71U8J1LodoJzujibKdd1jPbOq0wW+2S0qvN1KcvPb06 AK2J7QUrxbUyPdGESBXrmMGzhLYnCWTYrqc78XZpDaurA94xPQi8q4ZVU/J2xO8S1Q9XyiCPkvp1 DrVcNTNO7KHU5KlR6d4mj864CrnKInnWs2wHzxFqHXVE8S0UdRJPXYNG3356Cc2r7PCrIc8MnlNC c4dMKTcDxZqB4JYMPAN4uwU+UYhQiFCIUIhQiFCIUIhQiOjeyGjWq213AO/959MnPVvHZVMnPe+6 aPmkZ+sk5vRJz9YPTznpGc3wpOeyWdhdKEQ8R2j7Vk+7QgmfDM/CTl1q0VKjc1aXDi9oiua0dN2u APCpUO2BZlXwrtpZaSXPuTHu4m+VSJhBaM2GCMJKJJQSc1XermOcUe65Wajn4KlqNkxfnPt+gNXB u1OhFQe942/dh2agEKEQoRChEKEQoRChEKEQoRChEKEQkU7ox8jVLedOUIj4cQ5lCFGlayGFCIUI hQiFCIUIhYh0Qr7CEgoRvsISChEKEQoRChEKEQoRChEKEQoRChEKEQoRzn4QChHOfhAKEQoRChEK EQoRChG+MRIKEQoRw5VRonlOC+3iVGjncMhxGaEQoRChEKEQoRChEKEQoRChEKEQ8feEplYbbOG9 9GGkVFW1wU+RT7aUjLorBrm0hehgaTaYXVbDapfIwb8MEu+kq/J1KpRmwupgVkH1Gv5HB51RjPaO rt25Zrba5W6lpewRu3100AFndOdtC50JXDF9P9erg54deHuByE+xre9D7yw/qXegEKEQoRChEKEQ oRChEKEQoRChEKEQoRChEKEQkU7odsV5D27TMxuXnhIKEc8Q+rwf0X9HgjvetuKNcTbeGAmFCIUI hQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIWI3EIr0yWu+NVCq/M4Prnssl1ieA6tFvshlCEl 5zKvo+bgM2b+MdFktVhY5kspMWJNQj/+8EJuW7zsKi1n9MTvznyZ1UIhqcmRVAmtvNJuhXZk4DVn As8SOWhaP7QiJlt1DpmavFvinerXj1XkfsnPgEKEQoRChEKEQoRChEKEQoRCRHNRrSU1rGpEzn4+ vRBJ61TLjKmZb6G7LrqaLZshdXkO3VXRmTlp9b+zA9C58fnzSMGcl32GMf1Buhb6G0IzN6t5fgvN njhvEppdYLSUxiKjs2VKqRRaJVNKZRB4lUwpHSf17Lv6rVDKuP07K555z78xziZd8CVdCylENAWB vewzkE7I+xChEKEQoRChEKEQoRChEKEQMVQn/+vrq7xer9A5pOYF3r1TNLWHqW6h0bmi4+9JbGj5 cs32GWf/dpuu0Zq10H1uVH5O05TeyLCoNsZ2mxsUJdMiVVUHLXLASJ+FN8YZo9e7zUdO88t2Mjy2 770lvN/h328F0xYS9KZ/XZ5DPTe9kd876Hq41jxMa9Mx8KRu5W4ZRguH2OnaD0oNnMlQC23fN2jF PSrdK+xQBt4MprTQSNdOERppvaG4fc3vtspVC82eRD99uN4x45LvfmMsZV2Y4Vvo/YAj70G1ZX+v zrPqFho5eMvnN71+nL0uXHXv+7+3bHcYfh86DlDT7ae51p8j197XkNqlqSFj+zNqr7rhG+OsDRtr 6VrQNJNToZ1LUauGQStrf9x2WcQy5fBx2d1NbsYq9KZs8hXl6ZsfHbUyvRfG9BtjK39nGDQLhQiF CIWIdEJNd+oV6xqHWmhqwlsWtk42nDHcQtGiz+yylauGQ1poa47i1kSTUtanKIed1FHd9qzMl9ah TkQrPec+tCNjoZSgEOc7o932jC7b1V2lBLVQZLeFFYiMIt1ilGknde8Xq5rSmy3xzu3qmMen4kRc bZd1P3ZNnj/jTj3CaLedFiLZSbrgS3d96ln8/ZN6FIUIhQiFCIUIhQiFCIUIhYimvRauSFeYLXLB U2iXRYgN5QbdrXPt7cbhNIptleLuiNyuJ+wcimqpdPchhYhpAbwtl/0MhtPbzxi54oa2eooUOUj3 LEuXPRVWVOts4W5PF059dIQm3vaQ7qQuJWjiPBMKEX9faPSpH/7oGGXoaX8QGd4Kfdp/0nOjDGmh T6a9D62SeOeHUIZY3t+/D42iEKEQoRChEKEQoRChEKEQMVyx8kh/j3r9bS4QeUeEVPMugXfU1u1s FmoprdJTt/OO28ooVxKnHxRUIiisQOSUeFmGNbFNZTaI0AXeWUi34jx8Omb0i+TtsiwoRChEKESk Ewq/U4cFX2akGfeQrsuGkrfp94dfYR8RWqhppciFlacDxdplOC3DpSEhOtgd017QehZNTh1Kfx5k Rvd0Cc046B3PujHuQCFCIUIhQiFCIUIhQiFCIWI4Ay/61XZ49mNkb44znrX0tGdDo9H4a3cLHQPJ yGS3IaF3HpOBtz1elu4qi8C8DkIhQiFCIUIhQiHib6dzRZDuJX9avn0pkxbFrZQp5a/n24/KlJLw JX94bD91suERYfLVKEQoRChEKEQoRChEKEQoRKQTCimheUaqwmxbwlN3pKjyFUW6k1ohQiFCIUIh wik9It3EuQ9XQiFCIUIhQiEindC0EpoOpe8IG0obwDtBIUIhQiFCIUIhQiFCIUIhIp2QATwi96jj E+cYi0KMQoRChEKEATzCAB6R7qRWiFCIUIhQiFCIUIgwgEcoRChEKEQoRChEKEQoRChEpBMa3gOv lMVl6Wv3WjiYNunZu6HD6Dyje+AReJX9qT3wwkto7tge41vILecuSPfoUIhIJ9R1Us/cdLarhWbe ErqEZm4l1tVlPYW0a0l3UitEfAu5B94Ft0I7WumH0CNCCy3DoSlFRq9a6TjY50EP4ahRR/geeCMy pdw8Omq2mosUOagal9EGfcfPIi6Kyy7bxbNujDtQiFCIUIhQiFCIUIhQiFCIuM3AG3m77f2sdC2k EKEQoRChEKEQkU5oWlGtXtK1UDqhaRl427dPjUIhQiFCIUIhQiFCIcIAHqEQoRChEKEQoRChEKEQ oRCRTujXhNXuDJh0LaQQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRDxa/ZjdzwvXQspRChEKEQo RChEKEQoRChEpBMarhQXHfBL10IKEQoRChEKEQoRChEKEQoRChF5hd6rCe4qn/lDqJR9dTzfydtl PVVPZyzC7G6hWd1bnd7+/u2jymWi0Ov1uvzmq074X13WUxt/+vYY1D2fvxMJzn64fHm3wCcKEQoR ChEKEQoRChEKEQoR4SU0R4dIoS0UMV4LE1q2w1svvaOVEKHISYdhoVRR6Rnj/dDpmG3zQzOnY0JO 6sjxf7PQ7FzqJqEVid3VQquyzP9GCc3/1JZzt0J3W/TMkqpuoVVSTV22Qqr5HJotle4lP+yyj2ql 7haaJTXUZTOkhs+hrU/7WkZaadoL2vZix1FSoV0WIRV+Do2e5JbQJBQiFCIUIhQiFCIUIhQiFCLS CU3bA6+XdC2kEKEQoRChEKEQoRChEKEQoRChEKEQoRCRTmjacp2tCys/2bqw8oyRlv2VNLmbdCe1 QoRChEKEQoRChEKEQoRCRDqh2wBeKbGvtTWfjy0UtQq49nPSdVmV0Mr8jiUt1PKFntllpWysrhNN 6OLcnjJSLZ/XLDTKlPXU6cv99HZb7Reb1mVT1+Sv7LYpCW8jy36G8stmML1S3LYCAAdLc4N6ira1 8vz09rtvvT2/7E5ie2hha0pgutTkT1JUtZjVSunSuZ476jhja4mEGiIEzcAjFCIUIhQiFCIUIhQi FCIUItIJTcvA6/2s2xZKWXZstVS6c+i5EcU/Ey9rpUloRSs1BfBKmS/1zHhZdKjzjuee1Kta6dmh hRUn+HCsY3s9xjO212NMGVqY1XWh96Ht8bL0E+elJC0QmbIeYy/PfbgSqWqcH2zdJXAW/40Q59Ak hQE8QCFCIUIhQiFCIUIhQiFCISKdEG7jfHA3PJ6+0XWtyNnvTBt1fH19dU0ajM5+VHfZQc3M2fFv Pa11KtQSwD1+Nm1KLzL3Zzh7ajTPdfpuFD3nQMqx/QjfQpGrGkbmsPO2UBYUIhQiFCIUIvIKRcZQ lyTeriJ82WBoiHNGlKH1M09jHT2vssu3Aj8bpx3/HbnU4jYaNLv6wBnpXvJx5Pp+gOis3y6hWQe+ 4lk3xh0oRChEKEQoRChEKEQoRChEYAnNWtItrOyNr32Sbvny7aijphuuAnjbCiK9Xq/nbCffw9TV wtv3t49AIeJvC6W8U7+zvLjfO1HzjM1rPz6JnlWbsm9Qum16RhjuslIWTnq6a3JRiFGIUIhQiFCI cA88QiFCIUIhQiFCIUIhQiFCISKdkBl4hBl4XUJm4F0JmYF3Qroboxl4hEKEQoRChEKEQoQZeIQZ eMR/KwOvq8tnZOB9EnaVRb3kt3yxpoqVLWuFes+paRl4r9cr38LK9y9Q+2VC1g/dsX1P4FEUIhQi FCIUIhQiFCIUItIJmYFHTMnAGxGbkoE3wn8rA2/7uMz9OlagEDE1A+9PJLwNCd3NMW5LeIuUKWXC SZ1uIcH2p/0hEUVIC5098bc/7c/waT8DhQiFCIWI6UKhywZ7GL05ugceoRChEKEQoRChEKEQoRCh EJFOyAw84r+TgdfbUlWLc3sjiyEz+TuKsb2Dl/3QTuzOMU4gfOnp9NBCdFye+CUUGYPv4bSFrqRW iA2tyZ8xtYQTVrWtEiVXPYO2SqxrSm9mVw7PMUZXPXW5DpHu4Xq7Ss+qp2VCBt4ooRl4S1bH1LbS tNUxd0/6lgy80GHQ1UFaCF+u01vxJMUeeBEi1UIzDnrHs26MO1CIUIhQiFCIUIhQiFCIUIj4V8r8 Eerfra6zg3+l9K+9nzEKSddCChEKEQoRChEKEQoRChEKEQoRChEKEQoR6YQM4BEKEQoRChEKEQoR ChEKEQoR6YSmLM7972yPsQOFCIUIhQiFCIUIhQiFCIUIhYhnCbnlXAnOt5+yk0Bvvuoj9sDrYcoe eNPqU+/Y6NoMPOJZd+odKEQoRChEKEQoRChEKEQoRJxm4EW8qvZ+5pQWCo8o7qiqc/C/UmJHE6Gz HzPonv2I2mZnlNAWSrmx4zvD0zEZui2shVJsqHZHWC293d0W0kKRz8JToZ2tlO71Y1go+tXlUmhX t/2tLpvxptk0T72i28K6bPu+0rNaC4VWd1tIl0W+k1cJrWylv3UfKiU+IFMttKpo7d/qshmtZgCP UIhQiFCIUIhQiFCIUIhQiEgnNBzAi/7bdC00FMC72m6u92+/hTJtvp2my45GWRIEbuFSiD50+gza yvPo7sukmPR8/9tpJ/XSrZ5mVtD9uzHXUvr27Pz8m2ahlu7avjtXBH8rCHzWXXdfqKa7m4QeFZ6K oipM3sq0zJeD0USklr9f1mW1519T9lQLny0wvGzw7gN6zpHhFpp5id99oa4WmknuNWizDtJCeAYe QZ+ZbqXn8Aaz0Tzj4boThQiFCIUIhQiFCIUIhQiFiO81aFGVTUY/JzS0EPGlwsv9jBJW7mdZMZvV 9WNCyv1Edu3wHGNUV90K1R74jGWZL2fMuApD8zqmJ5qccVUmalleR2+RrV66shZaf95Cuqf9cJLA tqyFVQzfGKNP8O5o0Cy6umxmXDbs9WNJrvTdk3zWbHJTl5HE1AIANR8+47HyjBvj6LcMXYPW80q6 9OFae7Coe9MPoeg78tBynYjRw5ZX2FZaW8kAHqEQoRChEKEQoRChEKEQoRCRTug0A6+U2MhQcwDv EQUio8ZoYQUie5hej3H0AOH1GFtYVv4wZYiTmF5tkA44k/CY67QQJx346t9GCV2Tv3x+aHuyUkt2 3baY69n+QZGEvA9tL103k+EWSlUpbkbLpXunVohQiFCIUIhQiLCEJqEQoRChEKEQoRChEKEQoRCR Tug2A2+UJYVIZpNO6LvLRkcUqXbnigwiT+myJQlvV2zJ67giOt5fSnCXbV0tvC34UiMTyTODL+/M LDBaytMiisTW4Mvsrjp4xkKCd2bcje9oPoe2VorbXiLhndVddTCcXxbNlPyyEULyyyIJyy+L4ja/ bEce021+2Y5zCaNBI1IOpWcQNpSOIl0LKUQoRChEKEQoRChEpBP68ca4oooXka6F0gndvuRvHQZl QSFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiEindDtlN6OlQ7pWiid0I8uyxC7T9dCChEK EQoRChEKEaclNHc+09K10P9KmbuHSys5W6iUHO9CpTQugV9B3i4rJUe3PSeNYhe/hHbfk/K3UCkP eJalSudazaXQrm7rTgmcxXO6rJQ996RntVApm7Onapjdbc/rslKSZeCdkT7fPpLutNJZrfTcFirl AaGF5Rtd72A4vT1VqZYZNFU9PUhVkWA2ChEKEQoRChEKEZf7l72TftQxk3RC/0rZP/P6TroWUohQ iFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhIJ1Q1C7uSdC2UTuh0FnYn6VpIIUIhQiFCIUIh oroAwNbtMc7YvgT+EelcLoE/SB0mXx3T/yWUfs+XM7atON9e7Pjum2+/U5PA9CXwNQdwxfnBzpHs 1yvTOLo85Vm2E4UIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiF CIUIhQiFCIUIhQiFiHRC4dlTo8uR0rVQOiGzpwiFCIUIhQiFCIUIhYjTrIUUqTifMtvTuV6vV4ra nrnPoVL2V0CtSqNYKXWZxZl+I6NVKEQoRChEKEQoRChEKEQoRChEKEQxETWvAAAOpUlEQVQoRChE KEQoRChEKEQoRChEKEQoRChEKEQoRChEKERUbQV+FQSeEZe9FKqJRB+/Eyl22mWtYfHIMPqvFqqp enr2O19fXyEtdbo65k7m+LdZcf3bq4wOOmMFxI8uy7BqON19KJ1QdUnxVZwKpViDdrB7/5cfLdRT Wzj6C3wL7a5LfZDuKrsUcsnX/zEktKz6cs3BphfMPjtn3g/6vkZ2W9H1T4FPkRkn/g+hlgMse0Gj t0H6+Wh3WsGbUIhQiFCIUIhQiFCIUIi4HUo7ci0KMQoRChEKEVUBvFLWBfGqWuhuvB49PXMr1HKw KKmmc+iY+Zg5Z111Dl0F8aIk3sEWaj1pRwWHIoq1v9PClPvQSCuFCH220kir/c0WikQhQiHibwpF jnjx9WM1VeGpkZ+30rQG7b0rZr3S3hYi+TwotUb4CquzA9QeJOo1pOoqGwnotWIAj1CIUIhQiFCI UIhQiFCIUIhQiFCIUIhQiDADj0iXgVed+bIieFdKxTm0MnhXCqQErg7e/RJqZeqa/N1ZUwfD1Zcf EeIcQSFCISKv0Ejec+TuA8MtFL0VQu4MvNF09Yi7Nr5+tATvIjiNBvUccGq8rDUTL/IBW/W0TzHq mH3gK/LeqbOgEKEQoRChEKEQoRCRTqg6r+OOZesYd6AQoRChEKEQUT378c7MkWxXAO/9Z0tm8nvm F6OoCuAdrUBBvClCdzKf/z69ZFSGEFXeDLwMrVPKzUz+9lp66VooCwoRChHd9RhncVuPcQdhEcUo 0qUE/qpPfZXktiqAd1og8oyjfsPsd+yQAF4kGMBbPeowA49QiFCIUIhQiFCIUIhQiFCIUIhQiFCI UIhIl4E3VLFyxrTM8N5T0WmB1atjtq04b1l6M6PAdmgGXgShGXihiSYZWqeUhDP56fbAS/foSCc0 nMUZTboWyis04ybXQ94WykJIBt6yGufHwa72AD77/1HCMvBKmVhCs2f11JJX2JraDMsiijMPekfu yz4DChEKEQoRChEKEQoR6YTSTQs/ZzpmRU38M5qSJle8ylZnvqx6r666ynzJz4RCxL9S2nct2ZrO tZp0Qv9K4Zkz70OZUIhQiFCIUIhQiFCIUIhQiEgndDr7sTMpL10LKUQoRChEKEQoRChEKEQoRChE KEQoRChEdJXQLOU+gjSl2HFL9t30Bd47Vpof/Oqymi6a1TqnQncin/+2fA88YkZdz+ESmtE8p0Ck 2VP/h0KEQsRzhLZn4GUpqWcJTSJdCc1f70NnUrMl3hkqobn0fYgOtm358urbwXPu1LsIvzGOdnH+ geLZwc6+9az70lBexztTNwfdye1CgpUpybdCsw96R7ouU4hQiEgn9OOyz1ClKV0LKUQoRChEKEQ0 Jd6uyH8dfsmPrlhZVaGphqhhUdMMGu2BFyHVPfsxK4gXfpWNCg4H8JZGFHegEKEQoRChEKEQoRCh EJFOyD3wCIUIhQiFCIUIhQiFCIUIA3iEQsSvhZW7SddCChEKEd6pCYUIhQiFCIUIhQiFCIUIhQiF CIWIdEJONhAKEQoRChEKEQoRChEKEadr8t2m5w2FCMvSEwoRChHeqQmFCIUIhQiFCIUIhQiFCIUI hQiFCIUIhYj8QrvL0/8QWlE9h/i3u0U+Ga6MEk26Sc9/GVYzvJP/st+NQoRChHkdhEKEQoRChEJE UwnNT2YMCkJbKOJR0y00a7TSJTRz/BbSZZFvBc1CsweWTUIrhtpDXTbjBa5aaNXb5O2NccdERFeX zXzXDrsPRVG9X8fWvadq2P7oWLUzTlMLrRg4Dj/LtpeDnt11f+M+dMaSGud3zOq65z7taxltJUto EgoRChEKEQoRChEKEQoRBvAIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIWIdEKW0CQUIhQi FCIUIhQiFCIUIhQiFCIUIhQiFCKallq05gZdrYu9+5uqFvr6+rr88Kuf3S3SvftZeCpO7d98fX2d tlRTGsXxv1qRnr/BLM6zDzv+7fMD3//78++u/uaTKZVRWv7uUzB8CTzJ0M/T3YcUIhQiFCIUIhQi FCIUItIJmYFHKEQoRChEKEQoRChEKEQoRChEKEQoRChETA3gDQtdUROMW1YgsiUgF8Gt0FkXtgbk WukK4L3/+/ayY8So4HBEMVUJzRkoRChEKEQoRChEKEQoRKQTMoBHKEQoRChEKEQoRChEKEQoRChE KEQoRChEDMXLZgx6hxLeooN3l0KtEZ1IseptC1dt+/Rr9qO1aHZ0ke0fV1nEN/+7Abws28pftlDL N69ZcDAstAuFCIWIvEIjl27k4yNvC51R00pTV8dEPJdGPwPfh85evpa+D/UecOoatLtlXTNlLoXe D0RLvqLfhwzgEQoRChEKEQoRChEKEQoRChEKEQoRChEKEZcZeLUzaltygygDL3J65nJ+qCeIty2A dwjMkDIDj8gbwItke7zsquRqD3+zhSJRiFCICBGKfHxMaaF096ER0kUUqwN4pdQF8aa/D71DrRHx 5O+Ol82QQaGag7VGH4nud+pZPOuy34FChEKEQoSbgxIKEQoRChEKEQoRChEKEemEmmY/3rmLDo28 6HXHy2Zk310KjSQIjPJLqKeLpgqRyOe/Tw3g7Vz6fjAcwIsm3X3oMiVw16AxbwtlQSFCIeJSaFdm 8GVK4C6e02Wl1L2kLU8JPDvoDJGDX+9Dr9ereVvmSC4z8GqIjpVdCtUcbNZV2f0KO4tnXfY7UIhQ iFCIaFqMcsWy5O0dKEQoRChEKEQoRChEKESkE6reA2/VxPpwBl40KLR6rnF4CXw0VS/5K2dAsMtS TccYwCsKMQoRChEKEQoRChEKEemETDQhFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiwjLwokiXgXfa ZTsz8H4JnR3gWMp81RrTyo5dyZzJzZLqjpdtjUqvZGhh5YxWSheV7srrmEn3zkqzTurbfYNqWyZS rnojoxVl65qEfvzRxAdu131o5t266ll2xdT70PvlvXOj0L+VozhDGh8dZ9l3VzIR5xTuCVzLtIqV PVl1SypW1tRkWL7z9qyD3pHujVEhQiFCIUIhQiFCIUIhQiFCIeJ24nz7lN47u6Se0WU7UYj4V0p9 bOxg5mg2XQulE/pXCpfHTJXwthqFCIUIhQiFCIUIhQiFiOqaDSkrVq4Qe06XXUUWZ7/OGsAjFCIU IhQiFCIUIhQiFCIUIhQiFCIUIhQiqkto3hEZPUrXQgoRChEKEQoRChEKEQoRuYV6drWdXgCghRmh quoiEncV4SM5TXg74wjezV591RRR7P29FpoDeGc/25K8vYrc96EMKEQoRChEKEQoRChEKEQoRChE KEQoRKQTOs3AaxnMRk8+/O/sQ1LWsNpF6AxaaGG2LN0W1mXTaljVMqsFh6eFownpsu2bpaeYFl4F ttCqSpUHzV22JfNlZ7dVJyudsXwm/5MV96XnPu1TbFL8mP1cLSLxTvr8su0ZeCsk3nneObQahQiF CIUIhQiFCIUIhQiFCIUIhQiFiHRC3QG81r+p3XDktIVWTN1dfYHTiCKxdCa/lyVbzs3irkcuI4qR tLTeZQtdfcj7vy/fcq6VKZthtRK9pc9tiPOTnhZo/ZvbFloh8El3l/WkUdT8XnesYxZdMdfac63n SwzHXKNZttSi9jyrirmubKVpsY7eLxH66Ji6sWPkg7Pls5paaEVUKPwFLWSV3kya39fNwAMUIhQi FCIUIhQiFCIUIhQiFCIUIhQiFCIu98DrCeLV/t0dl/Gy1o36ImS+hSI+bEk6V01EKJqmWMcVU7On aAZ2Sw2rK7YlmtTOU29NxUmRaLKDrswXE012kvtO3XLQJZnAd6yaX69aP3TIrAjs/RJqPcjyEpqf rTK7634I1X7bmV2XN0ex9eE5q5X+F/lhEZ9jAI9QiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIjIWUKT DrKSrgy8gyVTeiNMXQK/i8uYa/p5amJ7Tc9Z3AaBa2Md20toziS/0KPC5CuoCpOvpKqFrlL80mcC R7AknauF7rRSVzaUYk3PUsrTuqyUzUHgMx6bmhzFs9JKU1WBT7+TwKqb5Heh2rsW+U8Xqr0t5bvj WfYtlGWBQ7ouU4hQiFCIUIhQiFCIUIhIJ1T1Tl3L344GZaH7nXrWFF9XC6UqMjore/Ng+Bz6b6YE njG7qw66u2zrxPmqWfxSnjbpueq8eec5k56p5hh3dNVBVZdtnWNceYmf0ZXwNpPL/LJSNk96ntHT YukrVraSTsh5akIhQiFCIUIhQiFCIUIhomsGbeZgoGqT4kNkBSi0emhU3UIHW2c/doxin3OV7Rrj P6eFdqEQoRChEPEMoe1ppcTKyawfrx8ZpoUvawsfbJk431Eq84rbOmg7uvBXHbTdM/qYo7iaqpTA 1Du8zUYhQiFCIUIhYmhB0wyem5q8iqZM4BSL4s6kti+sTJmB93q9LgtnbxE6SLUGbQUKEQoRChEK EemEbmfQHlOIZCYKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRP+YYdy9mKiVhCylE KEQoRChEfC/OzbCWupSTuh+7xXKuyX9faHKQorpOBqmcV9k7u1spfwvtRiFCIUIh4plC2zNf0u/O Vcq6l7fmFedbly/vyMxrKpFA/x7BZRGJXZl4TQu8V1A16ki5BH4VChEKEQoRChG/hFJOWL2ztZRv Bn7NMb6zrZTv7ioE7+Qcdbxn1u2OKn630G6Rg9xXWQYUIhQiFCIUIhQiFCIUIhQiFCIUIhQimmId pcwfUJ4K3U1aHT+rEXv/nNov0j2DNmumDWucv3+zT4m71uoV/lGxsnbCis6vkYmvripfLfHY1ovg dg3aHbOutl9FRrs+JHBKsLlw/xmpdiuNRiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCISKd0P8DU3MdyMKZsxcAAAAASUVORK5CYII= " + preserveAspectRatio="none" + height="1244.6" + width="9.5249996" + style="display:none" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#fd0000;fill-opacity:0.635071;stroke:none;stroke-width:0.264583;stroke-opacity:1" + x="-2.5308407e-06" + y="-873.23492" + id="text4630"><tspan + sodipodi:role="line" + x="-2.5308407e-06" + y="-873.23492" + id="tspan4634" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.5819px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#fd0000;fill-opacity:0.635071;stroke:none;stroke-width:0.264583;stroke-opacity:1" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;line-height:13.0757px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.221634" + x="-0.109361" + y="-256.69623" + id="text4642" + inkscape:export-xdpi="91.400002" + inkscape:export-ydpi="91.400002" + transform="scale(1.008509,0.9915628)"><tspan + sodipodi:role="line" + id="tspan94" + x="-0.109361" + y="-256.69623" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">А</tspan><tspan + sodipodi:role="line" + id="tspan96" + x="-0.109361" + y="-243.62054" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Б</tspan><tspan + sodipodi:role="line" + id="tspan98" + x="-0.109361" + y="-230.54485" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">В</tspan><tspan + sodipodi:role="line" + id="tspan100" + x="-0.109361" + y="-217.46915" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Г</tspan><tspan + sodipodi:role="line" + id="tspan102" + x="-0.109361" + y="-204.39345" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Д</tspan><tspan + sodipodi:role="line" + id="tspan104" + x="-0.109361" + y="-191.31775" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Е</tspan><tspan + sodipodi:role="line" + id="tspan106" + x="-0.109361" + y="-178.24205" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ж</tspan><tspan + sodipodi:role="line" + id="tspan108" + x="-0.109361" + y="-165.16635" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">З</tspan><tspan + sodipodi:role="line" + id="tspan110" + x="-0.109361" + y="-152.09065" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">И</tspan><tspan + sodipodi:role="line" + id="tspan112" + x="-0.109361" + y="-139.01495" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Й</tspan><tspan + sodipodi:role="line" + id="tspan114" + x="-0.109361" + y="-125.93924" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">К</tspan><tspan + sodipodi:role="line" + id="tspan116" + x="-0.109361" + y="-112.86354" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Л</tspan><tspan + sodipodi:role="line" + id="tspan118" + x="-0.109361" + y="-99.787842" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">М</tspan><tspan + sodipodi:role="line" + id="tspan120" + x="-0.109361" + y="-86.712143" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Н</tspan><tspan + sodipodi:role="line" + id="tspan122" + x="-0.109361" + y="-73.636444" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">О</tspan><tspan + sodipodi:role="line" + id="tspan124" + x="-0.109361" + y="-60.560741" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">П</tspan><tspan + sodipodi:role="line" + id="tspan126" + x="-0.109361" + y="-47.485043" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Р</tspan><tspan + sodipodi:role="line" + id="tspan128" + x="-0.109361" + y="-34.409344" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">С</tspan><tspan + sodipodi:role="line" + id="tspan130" + x="-0.109361" + y="-21.333645" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Т</tspan><tspan + sodipodi:role="line" + id="tspan132" + x="-0.109361" + y="-8.2579451" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">У</tspan><tspan + sodipodi:role="line" + id="tspan134" + x="-0.109361" + y="4.8177543" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ф</tspan><tspan + sodipodi:role="line" + id="tspan136" + x="-0.109361" + y="17.893454" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Х</tspan><tspan + sodipodi:role="line" + id="tspan138" + x="-0.109361" + y="30.969154" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ц</tspan><tspan + sodipodi:role="line" + id="tspan140" + x="-0.109361" + y="44.044853" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ч</tspan><tspan + sodipodi:role="line" + id="tspan142" + x="-0.109361" + y="57.120552" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ш</tspan><tspan + sodipodi:role="line" + id="tspan144" + x="-0.109361" + y="70.196251" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Щ</tspan><tspan + sodipodi:role="line" + id="tspan146" + x="-0.109361" + y="83.27195" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ь</tspan><tspan + sodipodi:role="line" + id="tspan148" + x="-0.109361" + y="96.347649" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ы</tspan><tspan + sodipodi:role="line" + id="tspan150" + x="-0.109361" + y="109.42335" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ъ</tspan><tspan + sodipodi:role="line" + id="tspan152" + x="-0.109361" + y="122.49905" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Э</tspan><tspan + sodipodi:role="line" + id="tspan154" + x="-0.109361" + y="135.57474" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ю</tspan><tspan + sodipodi:role="line" + id="tspan156" + x="-0.109361" + y="148.65044" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Я</tspan><tspan + sodipodi:role="line" + id="tspan158" + x="-0.109361" + y="161.72614" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">а</tspan><tspan + sodipodi:role="line" + id="tspan160" + x="-0.109361" + y="174.80183" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">б</tspan><tspan + sodipodi:role="line" + id="tspan162" + x="-0.109361" + y="187.87755" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">в</tspan><tspan + sodipodi:role="line" + id="tspan164" + x="-0.109361" + y="200.95325" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">г</tspan><tspan + sodipodi:role="line" + id="tspan166" + x="-0.109361" + y="214.02895" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">д</tspan><tspan + sodipodi:role="line" + id="tspan168" + x="-0.109361" + y="227.10464" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">е</tspan><tspan + sodipodi:role="line" + id="tspan170" + x="-0.109361" + y="240.18034" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ж</tspan><tspan + sodipodi:role="line" + id="tspan172" + x="-0.109361" + y="253.25604" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">з</tspan><tspan + sodipodi:role="line" + id="tspan174" + x="-0.109361" + y="266.33176" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">и</tspan><tspan + sodipodi:role="line" + id="tspan176" + x="-0.109361" + y="279.40744" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">й</tspan><tspan + sodipodi:role="line" + id="tspan178" + x="-0.109361" + y="292.48315" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">к</tspan><tspan + sodipodi:role="line" + id="tspan180" + x="-0.109361" + y="305.55884" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">л</tspan><tspan + sodipodi:role="line" + id="tspan182" + x="-0.109361" + y="318.63455" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">м</tspan><tspan + sodipodi:role="line" + id="tspan184" + x="-0.109361" + y="331.71027" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">н</tspan><tspan + sodipodi:role="line" + id="tspan186" + x="-0.109361" + y="344.78595" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">о</tspan><tspan + sodipodi:role="line" + id="tspan188" + x="-0.109361" + y="357.86166" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">п</tspan><tspan + sodipodi:role="line" + id="tspan190" + x="-0.109361" + y="370.93735" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">р</tspan><tspan + sodipodi:role="line" + id="tspan192" + x="-0.109361" + y="384.01306" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">с</tspan><tspan + sodipodi:role="line" + id="tspan194" + x="-0.109361" + y="397.08875" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">т</tspan><tspan + sodipodi:role="line" + id="tspan196" + x="-0.109361" + y="410.16446" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">у</tspan><tspan + sodipodi:role="line" + id="tspan198" + x="-0.109361" + y="423.24014" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ф</tspan><tspan + sodipodi:role="line" + id="tspan200" + x="-0.109361" + y="436.31586" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">х</tspan><tspan + sodipodi:role="line" + id="tspan202" + x="-0.109361" + y="449.39154" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ц</tspan><tspan + sodipodi:role="line" + id="tspan204" + x="-0.109361" + y="462.46725" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ч</tspan><tspan + sodipodi:role="line" + id="tspan206" + x="-0.109361" + y="475.54294" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ш</tspan><tspan + sodipodi:role="line" + id="tspan208" + x="-0.109361" + y="488.61865" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">щ</tspan><tspan + sodipodi:role="line" + id="tspan210" + x="-0.109361" + y="501.69434" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ь</tspan><tspan + sodipodi:role="line" + id="tspan212" + x="-0.109361" + y="514.77002" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ы</tspan><tspan + sodipodi:role="line" + id="tspan214" + x="-0.109361" + y="527.8457" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ъ</tspan><tspan + sodipodi:role="line" + id="tspan216" + x="-0.109361" + y="540.92139" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">э</tspan><tspan + sodipodi:role="line" + id="tspan218" + x="-0.109361" + y="553.99713" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ю</tspan><tspan + sodipodi:role="line" + id="tspan220" + x="-0.109361" + y="567.07281" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">я</tspan><tspan + sodipodi:role="line" + id="tspan222" + x="-0.109361" + y="580.1485" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">Ё</tspan><tspan + sodipodi:role="line" + id="tspan224" + x="-0.109361" + y="593.22418" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.9361px;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:0.221634">ё</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583" + x="0" + y="-1286.5312" + id="text5550"><tspan + sodipodi:role="line" + id="tspan5548" + x="0" + y="-1286.5312" + style="stroke-width:0.264583" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583" + x="0" + y="-1286.5312" + id="text8872"><tspan + sodipodi:role="line" + id="tspan8870" + x="0" + y="-1286.5312" + style="stroke-width:0.264583" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583" + x="0" + y="-1269.8625" + id="text8876"><tspan + sodipodi:role="line" + id="tspan8874" + x="0" + y="-1269.8625" + style="stroke-width:0.264583" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583" + x="0" + y="196.98749" + id="text4641"><tspan + sodipodi:role="line" + id="tspan4639" + x="0" + y="196.98749" + style="stroke-width:0.264583" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583" + x="0" + y="230.325" + id="text4649"><tspan + sodipodi:role="line" + id="tspan4647" + x="0" + y="230.325" + style="stroke-width:0.264583" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583" + x="0" + y="10.456248" + id="text4532"><tspan + sodipodi:role="line" + id="tspan4530" + x="0" + y="10.456248" + style="stroke-width:0.264583" /></text> + <image + sodipodi:absref="C:\Users\kiril\Documents\PlatformIO\Marlin\Marlin\src\lcd\extui\lib\ftdi_eve_touch_ui\ftdi_eve_lib\extended\unicode\font_bitmaps\romfont_31.pbm" + xlink:href="romfont_31.pbm" + width="9.5249996" + height="1244.6" + preserveAspectRatio="none" + id="image106" + x="13.229167" + y="-264.81683" /> + </g> +</svg> diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbm b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbm Binary files differnew file mode 100644 index 0000000..39cb670 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.pbm diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.png b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.png Binary files differnew file mode 100644 index 0000000..baafc82 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/romfont_31.png diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png Binary files differnew file mode 100644 index 0000000..ef68192 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg new file mode 100644 index 0000000..f803126 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.svg @@ -0,0 +1,443 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="38" + height="2107" + viewBox="0 0 10.054166 557.47707" + version="1.1" + id="svg8" + inkscape:version="0.92.4 (5da689c313, 2019-01-14)" + sodipodi:docname="western_char_set_bitmap_31.svg" + inkscape:export-filename="/home/aleph/git-repos/marlin-devel/tests/ftdi-eve-lib-examples/unicode_demo/src/ftdi_eve_lib/extended/unicode/font_bitmaps/western_char_set_bitmap_31.png" + inkscape:export-xdpi="96" + inkscape:export-ydpi="96"> + <defs + id="defs2" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="1" + inkscape:pageshadow="2" + inkscape:zoom="3.6948106" + inkscape:cx="-66.497155" + inkscape:cy="512.92836" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="true" + units="px" + inkscape:window-width="1330" + inkscape:window-height="965" + inkscape:window-x="59" + inkscape:window-y="18" + inkscape:window-maximized="0"> + <inkscape:grid + type="xygrid" + id="grid4838" + spacingx="10.583333" + spacingy="12.964583" + originy="0" + empspacing="1" + color="#000000" + opacity="0" + originx="8.1491663" + empcolor="#3fff69" + empopacity="0.25098039" /> + <inkscape:grid + type="xygrid" + id="grid4528" + spacingx="10.583333" + spacingy="12.964583" + originx="0" + originy="2.6987499" + color="#c93f24" + opacity="0.1254902" + dotted="false" + empspacing="1" + visible="true" /> + <inkscape:grid + type="xygrid" + id="grid4530" + spacingx="10.583333" + spacingy="12.964583" + color="#3f5fff" + opacity="0.69019608" + originy="8.8106248" + empcolor="#593fff" + empopacity="0.25098039" + empspacing="1" + visible="true" + enabled="true" /> + <inkscape:grid + type="xygrid" + id="grid4532" + spacingx="10.583333" + spacingy="12.964583" + empspacing="1" + color="#ffa03f" + opacity="0.1254902" + originy="10.689166" + visible="true" /> + <inkscape:grid + type="xygrid" + id="grid4653" + empcolor="#ff663f" + empopacity="0.25098039" + spacingx="10.583333" + spacingy="12.964583" + originy="6.6145831" + visible="false" /> + </sodipodi:namedview> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(0,260.47708)"> + <image + y="-947.59998" + x="-1.7763568e-15" + id="image4606" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAABJgCAYAAACFiF0FAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnetu6zrSKJnBev9X9vlxPgWOI6l4aZKt7CpgMNgriVUmdSOb3fx6vV6vkoj/7Rb4RCFCIUIh QiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiHi3/t/fH19 /fjhjkUP6VpIIUIhQiFCIUIhQiFCIUIhQiHixzt1hoXD6VpIIUIhwpEroRDhnZpQiFCIUIhQiFCI UIhQiFCISCdUNQxaOTxK10IKEQoRzxG6urRnj26f00K7OBXa1V2llPJlVQtAIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiFCIUIhQiFCIUIhQiHiH//K/+c9iHc2cUs/ryVdCz1TaFV3VQutRCEindCPaNDn goEIWk/ydC2UTgiXL6+8B5WSsIWqhejbR0VKb4XoqptxVT63y1aRTujr9Xq9MtyhD9K1UDqhf6Xk uEMfpGuhZwjt6q5LoZ0oRChEuAaNUIhQiFCIUIhQiEgnVB1aOJj5+lpKwhZSiEgnVHVSX82OzDjB cUqvdqomakrnUqjnABFSp1129sE0pH7/t+khzpWpOb+EWpu9tuW6hWoO2PM7taS7D6UTan7aX7Hk xljKnHjGHb+Eoq+aVqrPoVVSTTmKLc+2Xm7nh2oOvnQWtuZg0a1WdaeuFYuga0rv7uBbVsfctdpo Sw09OlKOy5a/ftQQ2VJWGyRyC3120eox2S+hqINNHwbdDaWjn/6nj46Rg0x5dPR+aMRt4vIl/6rU zywRFDo72Oz5xVKy34cykE6oaeS64mGbroUUIhQiFCIUIhQiFCLSCQ2Fp2ZQHQ1aMQP7S6jmgLOl cBh0JjIaNbzju4VoiNMiMNK94VfZ1knPTyLOr2n3oe1pFOGZwFdj+OgDEpeXfcv5MC3xtickPj0D 724Vw4rn2WmX1R54+XKd1TKlPOV9iLhrndF3qbB1jHe3ieNnNWIhXRYZgmhqoZoTeTSg17Wyobar 6HOGhGqIWBoWUkQikqbwlLOwn7S2zvRX2EPiToZEP0cg9PtN0aAaUow6aqVrfi98ld7yhythMZvZ KEQoRChEKEQoRChEKEQoRAylBM4YyQ7NU88IUw13WXSksSvmOjOqWBVz/eyWmflD3Rl4LqzcRUho oZSJsY6amfmlVxkxexnG0KMjWqaUgRXnswJ6l102Mq84Qmh6ewS/zqFdIgdd6e0UG3v/XyvfLdR6 Oc9aslN9Uq/KEP5fywe3SvW0YPN9aHZLdWdxfhL1Ktv9tJ9VazhnWmlv5t3Z3179W5PQGbXjsuhL /3SF1d0Bj/+uWcnQw9Qq8D1dF5ISeDeIbJW6XdDUeheOaGFLaBIKEQoRChEKEQoRChEKEQoR6YSs rkMoRChEdM3kz+Q5LbSL0PpDEaRrIdwDbzXpWkghQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFC IUIhIp1QeDGbUbqK2cykuXZMKZvW5F9hMZsrmVVUd9m2qqcHu9IpToV2RqfT3am7cxRnUZXFuZLn ddlqqmpYreSH0O7zp5SnddkOFCIUIhQiFCJ+CKVfjJJ61LEKhQgsIrGaprH9CvJ3WSljibijPKOF StnXSrmHQcTyTWjOWN114WU2Rkk3pefGjoRChEJEU+2YFXyVUr6v5d1vi6VknNLb+TJ2xnCplmhu K6PsIHd4KkPX5bwxvrO7lfK3UCkPyC9z5JqJ56SVXhXTms1zWmgXChEKEQoRChHPEdq1Du05LbSL ZwptX8eYYrIhC7iOcfvCynfSh6dWcDnHuP0lf/fc4sHpPHWqyYbdc435Js5rNpFdyek89U5y34cy oBChEKEQoRChEKEQkU4IV1ilynPdgULEZfVl2pmr5veGha4Oevdv0QwPpaMlv1uodXvUWbeA5l1x thUAuGqlLauFU2eTr9r77qA6eXvVMp7LnZWutiWctV0hCu0i3bNMIUIhQiFCIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiEinVB1AYBVE6HpWkghQiFCISKd0PeNsTV2Qb/fe+NM10LphE5jrmf4LMuCQoRC hEJEOqHqUYdJk1lQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiLhc +7G9UlwWFCIUIk6FUlUb3E1+od3Z7tVLvlaRv8t2oxChEKEQoRChEKEQoRChEKEQoRChEKEQoRCR TuiyLmwNM2ZM0rVQOqEfXZZh0ipdCylEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQo RChEKEQoRChEKEQoRChEKEQoRNwutdgRx0/XQgoRrv0gFCIUIhQiFCIUIhQiFCIUItIJVRfuf+d9 uBT92tvcQq3L5FsZ6rLta/Jnt04pAy3kNj2frOiuUjpbaOYI95ldtqq7SuloodkTEii0snVKaWyh FdM1zzqpV3dXKQ0t5L5Bn+zorlIqW2jlZOip0K7WKaWihVZPFec/qXd2VynQQkaDyofQ7u4q5aaF ttf0zNA6pVy0kPUY3/hfKXm6q5STFtodVUzXZf9K2d8q76RrIYUIhQiFCIUIhQiFCIWIqgDe1Svu jPeoS6Ga9+zjdyLFQuaHIgcJ1bMfr9fr+38zpaomrD4lrsQipG4nG+jc2B5zXcHlZEPtt//8vdFu y9tCWVCIUIhQiFCIUIhQiMgr1PteE50ClreFSmlvpRkxEhy5ng0GZ45kv14nn9LzzaNGICEBvMjh 0GWXHQdZOdFwKzT7wFfkvuwzoBChEKEQoRChEKEQoRDxbKHjdXbmErFfr7A7xmLv5O6yDKv1fg2l j1HG5/9vETrYKZX7HMqAQoRChEKEQoRChEKEQoRChEKEQoRCRDqh6vpDFgDIgkKEQoRChEKEQoRC hEKEQsRQBl4p8a+2t0I7svDCalhFBf9OW+jsw2vWyX59fcWvFq6ROf5tS8Jb60FD88t6FmtvL1Q7 m3RCf297jP9WkkAGhoRmbOvTLTRrj6EuoZmraJqFap91vXQt+ZolU8rgSb01vX3VRllVQqmqL684 b965FVotU0rjS/626su7ZEqpPKlXvifd7oG3g+Gh9BW9rfq33odm8Pde8qNRiFCIUIhQiFCIUIhQ iFCISCf0nBKadyJnP586x/j19bUtgFcVLztYUUazuxDJVeWU0ajicNLk0knP7Vus7MrcfOdXC+2W Snen/lsBvC1FtWoPvDU89cm2aNAVPc++y886KzvWIvLJ1pN6Rkno4S5LFcA7iKzA/Pfu1NFcvjGm 2Edxt0wpHRHF2dxWrKwl8onfFQRu+XkrTRUrV5TRPH39eL1elwsnZ3PZZT1lNCMeI7cvaKsqnVYL zTzwFfkfHbtRiFCIUIhQiFCIUIhQiFCIqH6FfWfmStB0LRSyJj+SZ7fQ1pHrJ6umZp7ZZasyFkrp mB/atiZ/F01zjNuSBM7YPvuRYp76YEdXHeQ/qXe2TinZl1pkSDT5FtrdVQfpTuqv1+v1mtFVpuLM 4l8pfc2bKjV5JgoRChHphLpmP0rZnLy9EoUIhQiFCIUIhQiFCIUIhYh0QtX1GGuxMNtsqkYdTgtn Iv889e76MU1ppStIdw5VTzasKrSFQnddGF3ouJSE+WXdC7xnnfwYDbpaaz8jt+yX0OdB6NxYclKP HiQ0m7yHlBl4kShEmIFHhKe3jxKeEhg6Lmt9HMzo2q41aFdP94ibZFNK4B1Tg8Ct2XSRj4+qDLw0 5X5mHviK/I+O3ShEKEQoRChEKEQoRChEKEQ0rUG7GvpEbKT2fQwqqtUyJJq+b9D26jrv3I1MqZTm CNUj1+2pOO9sHZelC+Dt5ja0sD3zJQPDd+pSNsTLKB4WeQMd3j7183enFNU6Y0sAr1bm+LflBSJr nlePCE9tLxCZLkweiUJEbqFVN787wtZ+vLO1YmU0w0u+lpTQvDvQ7AhRczrX7K3lb0to7gjiVe+1 kGYN2syDn5H7Tp0BhQiFCIUIhQiFCIUIhQiFiO9X2OjxleV+ZvHdZSOjisjuntJCW7MWUm8XNj0q vYNuoVQ1rGZGHp/fZbPjskMtNGOKpkkodW1hS0btoivRZGux49UoRDRHg6xPvRuFCIUIhYju3dtn ka6FFCIUIhQiFCIUIhQiFCIUItIJVa1Bm71U8J1LodoJzujibKdd1jPbOq0wW+2S0qvN1KcvPb06 AK2J7QUrxbUyPdGESBXrmMGzhLYnCWTYrqc78XZpDaurA94xPQi8q4ZVU/J2xO8S1Q9XyiCPkvp1 DrVcNTNO7KHU5KlR6d4mj864CrnKInnWs2wHzxFqHXVE8S0UdRJPXYNG3356Cc2r7PCrIc8MnlNC c4dMKTcDxZqB4JYMPAN4uwU+UYhQiFCIUIhQiFCIUIhQiOjeyGjWq213AO/959MnPVvHZVMnPe+6 aPmkZ+sk5vRJz9YPTznpGc3wpOeyWdhdKEQ8R2j7Vk+7QgmfDM/CTl1q0VKjc1aXDi9oiua0dN2u APCpUO2BZlXwrtpZaSXPuTHu4m+VSJhBaM2GCMJKJJQSc1XermOcUe65Wajn4KlqNkxfnPt+gNXB u1OhFQe942/dh2agEKEQoRChEKEQoRChEKEQoRChEKEQkU7ox8jVLedOUIj4cQ5lCFGlayGFCIUI hQiFCIUIhYh0Qr7CEgoRvsISChEKEQoRChEKEQoRChEKEQoRChEKEQoRzn4QChHOfhAKEQoRChEK EQoRChG+MRIKEQoRw5VRonlOC+3iVGjncMhxGaEQoRChEKEQoRChEKEQoRChEKEQ8feEplYbbOG9 9GGkVFW1wU+RT7aUjLorBrm0hehgaTaYXVbDapfIwb8MEu+kq/J1KpRmwupgVkH1Gv5HB51RjPaO rt25Zrba5W6lpewRu3100AFndOdtC50JXDF9P9erg54deHuByE+xre9D7yw/qXegEKEQoRChEKEQ oRChEKEQoRChEKEQoRChEKEQkU7odsV5D27TMxuXnhIKEc8Q+rwf0X9HgjvetuKNcTbeGAmFCIUI hQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIWI3EIr0yWu+NVCq/M4Prnssl1ieA6tFvshlCEl 5zKvo+bgM2b+MdFktVhY5kspMWJNQj/+8EJuW7zsKi1n9MTvznyZ1UIhqcmRVAmtvNJuhXZk4DVn As8SOWhaP7QiJlt1DpmavFvinerXj1XkfsnPgEKEQoRChEKEQoRChEKEQoRCRHNRrSU1rGpEzn4+ vRBJ61TLjKmZb6G7LrqaLZshdXkO3VXRmTlp9b+zA9C58fnzSMGcl32GMf1Buhb6G0IzN6t5fgvN njhvEppdYLSUxiKjs2VKqRRaJVNKZRB4lUwpHSf17Lv6rVDKuP07K555z78xziZd8CVdCylENAWB vewzkE7I+xChEKEQoRChEKEQoRChEKEQMVQn/+vrq7xer9A5pOYF3r1TNLWHqW6h0bmi4+9JbGj5 cs32GWf/dpuu0Zq10H1uVH5O05TeyLCoNsZ2mxsUJdMiVVUHLXLASJ+FN8YZo9e7zUdO88t2Mjy2 770lvN/h328F0xYS9KZ/XZ5DPTe9kd876Hq41jxMa9Mx8KRu5W4ZRguH2OnaD0oNnMlQC23fN2jF PSrdK+xQBt4MprTQSNdOERppvaG4fc3vtspVC82eRD99uN4x45LvfmMsZV2Y4Vvo/YAj70G1ZX+v zrPqFho5eMvnN71+nL0uXHXv+7+3bHcYfh86DlDT7ae51p8j197XkNqlqSFj+zNqr7rhG+OsDRtr 6VrQNJNToZ1LUauGQStrf9x2WcQy5fBx2d1NbsYq9KZs8hXl6ZsfHbUyvRfG9BtjK39nGDQLhQiF CIWIdEJNd+oV6xqHWmhqwlsWtk42nDHcQtGiz+yylauGQ1poa47i1kSTUtanKIed1FHd9qzMl9ah TkQrPec+tCNjoZSgEOc7o932jC7b1V2lBLVQZLeFFYiMIt1ilGknde8Xq5rSmy3xzu3qmMen4kRc bZd1P3ZNnj/jTj3CaLedFiLZSbrgS3d96ln8/ZN6FIUIhQiFCIUIhQiFCIUIhYimvRauSFeYLXLB U2iXRYgN5QbdrXPt7cbhNIptleLuiNyuJ+wcimqpdPchhYhpAbwtl/0MhtPbzxi54oa2eooUOUj3 LEuXPRVWVOts4W5PF059dIQm3vaQ7qQuJWjiPBMKEX9faPSpH/7oGGXoaX8QGd4Kfdp/0nOjDGmh T6a9D62SeOeHUIZY3t+/D42iEKEQoRChEKEQoRChEKEQMVyx8kh/j3r9bS4QeUeEVPMugXfU1u1s FmoprdJTt/OO28ooVxKnHxRUIiisQOSUeFmGNbFNZTaI0AXeWUi34jx8Omb0i+TtsiwoRChEKESk Ewq/U4cFX2akGfeQrsuGkrfp94dfYR8RWqhppciFlacDxdplOC3DpSEhOtgd017QehZNTh1Kfx5k Rvd0Cc046B3PujHuQCFCIUIhQiFCIUIhQiFCIWI4Ay/61XZ49mNkb44znrX0tGdDo9H4a3cLHQPJ yGS3IaF3HpOBtz1elu4qi8C8DkIhQiFCIUIhQiHib6dzRZDuJX9avn0pkxbFrZQp5a/n24/KlJLw JX94bD91suERYfLVKEQoRChEKEQoRChEKEQoRKQTCimheUaqwmxbwlN3pKjyFUW6k1ohQiFCIUIh wik9It3EuQ9XQiFCIUIhQiEindC0EpoOpe8IG0obwDtBIUIhQiFCIUIhQiFCIUIhIp2QATwi96jj E+cYi0KMQoRChEKEATzCAB6R7qRWiFCIUIhQiFCIUIgwgEcoRChEKEQoRChEKEQoRChEpBMa3gOv lMVl6Wv3WjiYNunZu6HD6Dyje+AReJX9qT3wwkto7tge41vILecuSPfoUIhIJ9R1Us/cdLarhWbe ErqEZm4l1tVlPYW0a0l3UitEfAu5B94Ft0I7WumH0CNCCy3DoSlFRq9a6TjY50EP4ahRR/geeCMy pdw8Omq2mosUOagal9EGfcfPIi6Kyy7bxbNujDtQiFCIUIhQiFCIUIhQiFCIuM3AG3m77f2sdC2k EKEQoRChEKEQkU5oWlGtXtK1UDqhaRl427dPjUIhQiFCIUIhQiFCIcIAHqEQoRChEKEQoRChEKEQ oRCRTujXhNXuDJh0LaQQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRDxa/ZjdzwvXQspRChEKEQo RChEKEQoRChEpBMarhQXHfBL10IKEQoRChEKEQoRChEKEQoRChF5hd6rCe4qn/lDqJR9dTzfydtl PVVPZyzC7G6hWd1bnd7+/u2jymWi0Ov1uvzmq074X13WUxt/+vYY1D2fvxMJzn64fHm3wCcKEQoR ChEKEQoRChEKEQoR4SU0R4dIoS0UMV4LE1q2w1svvaOVEKHISYdhoVRR6Rnj/dDpmG3zQzOnY0JO 6sjxf7PQ7FzqJqEVid3VQquyzP9GCc3/1JZzt0J3W/TMkqpuoVVSTV22Qqr5HJotle4lP+yyj2ql 7haaJTXUZTOkhs+hrU/7WkZaadoL2vZix1FSoV0WIRV+Do2e5JbQJBQiFCIUIhQiFCIUIhQiFCLS CU3bA6+XdC2kEKEQoRChEKEQoRChEKEQoRChEKEQoRCRTmjacp2tCys/2bqw8oyRlv2VNLmbdCe1 QoRChEKEQoRChEKEQoRCRDqh2wBeKbGvtTWfjy0UtQq49nPSdVmV0Mr8jiUt1PKFntllpWysrhNN 6OLcnjJSLZ/XLDTKlPXU6cv99HZb7Reb1mVT1+Sv7LYpCW8jy36G8stmML1S3LYCAAdLc4N6ira1 8vz09rtvvT2/7E5ie2hha0pgutTkT1JUtZjVSunSuZ476jhja4mEGiIEzcAjFCIUIhQiFCIUIhQi FCIUItIJTcvA6/2s2xZKWXZstVS6c+i5EcU/Ey9rpUloRSs1BfBKmS/1zHhZdKjzjuee1Kta6dmh hRUn+HCsY3s9xjO212NMGVqY1XWh96Ht8bL0E+elJC0QmbIeYy/PfbgSqWqcH2zdJXAW/40Q59Ak hQE8QCFCIUIhQiFCIUIhQiFCISKdEG7jfHA3PJ6+0XWtyNnvTBt1fH19dU0ajM5+VHfZQc3M2fFv Pa11KtQSwD1+Nm1KLzL3Zzh7ajTPdfpuFD3nQMqx/QjfQpGrGkbmsPO2UBYUIhQiFCIUIvIKRcZQ lyTeriJ82WBoiHNGlKH1M09jHT2vssu3Aj8bpx3/HbnU4jYaNLv6wBnpXvJx5Pp+gOis3y6hWQe+ 4lk3xh0oRChEKEQoRChEKEQoRChEYAnNWtItrOyNr32Sbvny7aijphuuAnjbCiK9Xq/nbCffw9TV wtv3t49AIeJvC6W8U7+zvLjfO1HzjM1rPz6JnlWbsm9Qum16RhjuslIWTnq6a3JRiFGIUIhQiFCI cA88QiFCIUIhQiFCIUIhQiFCISKdkBl4hBl4XUJm4F0JmYF3Qroboxl4hEKEQoRChEKEQoQZeIQZ eMR/KwOvq8tnZOB9EnaVRb3kt3yxpoqVLWuFes+paRl4r9cr38LK9y9Q+2VC1g/dsX1P4FEUIhQi FCIUIhQiFCIUItIJmYFHTMnAGxGbkoE3wn8rA2/7uMz9OlagEDE1A+9PJLwNCd3NMW5LeIuUKWXC SZ1uIcH2p/0hEUVIC5098bc/7c/waT8DhQiFCIWI6UKhywZ7GL05ugceoRChEKEQoRChEKEQoRCh EJFOyAw84r+TgdfbUlWLc3sjiyEz+TuKsb2Dl/3QTuzOMU4gfOnp9NBCdFye+CUUGYPv4bSFrqRW iA2tyZ8xtYQTVrWtEiVXPYO2SqxrSm9mVw7PMUZXPXW5DpHu4Xq7Ss+qp2VCBt4ooRl4S1bH1LbS tNUxd0/6lgy80GHQ1UFaCF+u01vxJMUeeBEi1UIzDnrHs26MO1CIUIhQiFCIUIhQiFCIUIj4V8r8 Eerfra6zg3+l9K+9nzEKSddCChEKEQoRChEKEQoRChEKEQoRChEKEQoR6YQM4BEKEQoRChEKEQoR ChEKEQoR6YSmLM7972yPsQOFCIUIhQiFCIUIhQiFCIUIhYhnCbnlXAnOt5+yk0Bvvuoj9sDrYcoe eNPqU+/Y6NoMPOJZd+odKEQoRChEKEQoRChEKEQoRJxm4EW8qvZ+5pQWCo8o7qiqc/C/UmJHE6Gz HzPonv2I2mZnlNAWSrmx4zvD0zEZui2shVJsqHZHWC293d0W0kKRz8JToZ2tlO71Y1go+tXlUmhX t/2tLpvxptk0T72i28K6bPu+0rNaC4VWd1tIl0W+k1cJrWylv3UfKiU+IFMttKpo7d/qshmtZgCP UIhQiFCIUIhQiFCIUIhQiEgnNBzAi/7bdC00FMC72m6u92+/hTJtvp2my45GWRIEbuFSiD50+gza yvPo7sukmPR8/9tpJ/XSrZ5mVtD9uzHXUvr27Pz8m2ahlu7avjtXBH8rCHzWXXdfqKa7m4QeFZ6K oipM3sq0zJeD0USklr9f1mW1519T9lQLny0wvGzw7gN6zpHhFpp5id99oa4WmknuNWizDtJCeAYe QZ+ZbqXn8Aaz0Tzj4boThQiFCIUIhQiFCIUIhQiFiO81aFGVTUY/JzS0EPGlwsv9jBJW7mdZMZvV 9WNCyv1Edu3wHGNUV90K1R74jGWZL2fMuApD8zqmJ5qccVUmalleR2+RrV66shZaf95Cuqf9cJLA tqyFVQzfGKNP8O5o0Cy6umxmXDbs9WNJrvTdk3zWbHJTl5HE1AIANR8+47HyjBvj6LcMXYPW80q6 9OFae7Coe9MPoeg78tBynYjRw5ZX2FZaW8kAHqEQoRChEKEQoRChEKEQoRCRTug0A6+U2MhQcwDv EQUio8ZoYQUie5hej3H0AOH1GFtYVv4wZYiTmF5tkA44k/CY67QQJx346t9GCV2Tv3x+aHuyUkt2 3baY69n+QZGEvA9tL103k+EWSlUpbkbLpXunVohQiFCIUIhQiLCEJqEQoRChEKEQoRChEKEQoRCR Tug2A2+UJYVIZpNO6LvLRkcUqXbnigwiT+myJQlvV2zJ67giOt5fSnCXbV0tvC34UiMTyTODL+/M LDBaytMiisTW4Mvsrjp4xkKCd2bcje9oPoe2VorbXiLhndVddTCcXxbNlPyyEULyyyIJyy+L4ja/ bEce021+2Y5zCaNBI1IOpWcQNpSOIl0LKUQoRChEKEQoRChEpBP68ca4oooXka6F0gndvuRvHQZl QSFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiEindDtlN6OlQ7pWiid0I8uyxC7T9dCChEK EQoRChEKEaclNHc+09K10P9KmbuHSys5W6iUHO9CpTQugV9B3i4rJUe3PSeNYhe/hHbfk/K3UCkP eJalSudazaXQrm7rTgmcxXO6rJQ996RntVApm7Onapjdbc/rslKSZeCdkT7fPpLutNJZrfTcFirl AaGF5Rtd72A4vT1VqZYZNFU9PUhVkWA2ChEKEQoRChEKEZf7l72TftQxk3RC/0rZP/P6TroWUohQ iFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhIJ1Q1C7uSdC2UTuh0FnYn6VpIIUIhQiFCIUIh oroAwNbtMc7YvgT+EelcLoE/SB0mXx3T/yWUfs+XM7atON9e7Pjum2+/U5PA9CXwNQdwxfnBzpHs 1yvTOLo85Vm2E4UIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiF CIUIhQiFCIUIhQiFiHRC4dlTo8uR0rVQOiGzpwiFCIUIhQiFCIUIhYjTrIUUqTifMtvTuV6vV4ra nrnPoVL2V0CtSqNYKXWZxZl+I6NVKEQoRChEKEQoRChEKEQoRChEKEQxETWvAAAOpUlEQVQoRChE KEQoRChEKEQoRChEKEQoRChEKEQoRChEKERUbQV+FQSeEZe9FKqJRB+/Eyl22mWtYfHIMPqvFqqp enr2O19fXyEtdbo65k7m+LdZcf3bq4wOOmMFxI8uy7BqON19KJ1QdUnxVZwKpViDdrB7/5cfLdRT Wzj6C3wL7a5LfZDuKrsUcsnX/zEktKz6cs3BphfMPjtn3g/6vkZ2W9H1T4FPkRkn/g+hlgMse0Gj t0H6+Wh3WsGbUIhQiFCIUIhQiFCIUIi4HUo7ci0KMQoRChEKEVUBvFLWBfGqWuhuvB49PXMr1HKw KKmmc+iY+Zg5Z111Dl0F8aIk3sEWaj1pRwWHIoq1v9PClPvQSCuFCH220kir/c0WikQhQiHibwpF jnjx9WM1VeGpkZ+30rQG7b0rZr3S3hYi+TwotUb4CquzA9QeJOo1pOoqGwnotWIAj1CIUIhQiFCI UIhQiFCIUIhQiFCIUIhQiDADj0iXgVed+bIieFdKxTm0MnhXCqQErg7e/RJqZeqa/N1ZUwfD1Zcf EeIcQSFCISKv0Ejec+TuA8MtFL0VQu4MvNF09Yi7Nr5+tATvIjiNBvUccGq8rDUTL/IBW/W0TzHq mH3gK/LeqbOgEKEQoRChEKEQoRCRTqg6r+OOZesYd6AQoRChEKEQUT378c7MkWxXAO/9Z0tm8nvm F6OoCuAdrUBBvClCdzKf/z69ZFSGEFXeDLwMrVPKzUz+9lp66VooCwoRChHd9RhncVuPcQdhEcUo 0qUE/qpPfZXktiqAd1og8oyjfsPsd+yQAF4kGMBbPeowA49QiFCIUIhQiFCIUIhQiFCIUIhQiFCI UIhIl4E3VLFyxrTM8N5T0WmB1atjtq04b1l6M6PAdmgGXgShGXihiSYZWqeUhDP56fbAS/foSCc0 nMUZTboWyis04ybXQ94WykJIBt6yGufHwa72AD77/1HCMvBKmVhCs2f11JJX2JraDMsiijMPekfu yz4DChEKEQoRChEKEQoR6YTSTQs/ZzpmRU38M5qSJle8ylZnvqx6r666ynzJz4RCxL9S2nct2ZrO tZp0Qv9K4Zkz70OZUIhQiFCIUIhQiFCIUIhQiEgndDr7sTMpL10LKUQoRChEKEQoRChEKEQoRChE KEQoRChEdJXQLOU+gjSl2HFL9t30Bd47Vpof/Oqymi6a1TqnQncin/+2fA88YkZdz+ESmtE8p0Ck 2VP/h0KEQsRzhLZn4GUpqWcJTSJdCc1f70NnUrMl3hkqobn0fYgOtm358urbwXPu1LsIvzGOdnH+ geLZwc6+9az70lBexztTNwfdye1CgpUpybdCsw96R7ouU4hQiEgn9OOyz1ClKV0LKUQoRChEKEQ0 Jd6uyH8dfsmPrlhZVaGphqhhUdMMGu2BFyHVPfsxK4gXfpWNCg4H8JZGFHegEKEQoRChEKEQoRCh EJFOyD3wCIUIhQiFCIUIhQiFCIUIA3iEQsSvhZW7SddCChEKEd6pCYUIhQiFCIUIhQiFCIUIhQiF CIWIdEJONhAKEQoRChEKEQoRChEKEadr8t2m5w2FCMvSEwoRChHeqQmFCIUIhQiFCIUIhQiFCIUI hQiFCIUIhYj8QrvL0/8QWlE9h/i3u0U+Ga6MEk26Sc9/GVYzvJP/st+NQoRChHkdhEKEQoRChEJE UwnNT2YMCkJbKOJR0y00a7TSJTRz/BbSZZFvBc1CsweWTUIrhtpDXTbjBa5aaNXb5O2NccdERFeX zXzXDrsPRVG9X8fWvadq2P7oWLUzTlMLrRg4Dj/LtpeDnt11f+M+dMaSGud3zOq65z7taxltJUto EgoRChEKEQoRChEKEQoRBvAIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIWIdEKW0CQUIhQi FCIUIhQiFCIUIhQiFCIUIhQiFCKallq05gZdrYu9+5uqFvr6+rr88Kuf3S3SvftZeCpO7d98fX2d tlRTGsXxv1qRnr/BLM6zDzv+7fMD3//78++u/uaTKZVRWv7uUzB8CTzJ0M/T3YcUIhQiFCIUIhQi FCIUItIJmYFHKEQoRChEKEQoRChEKEQoRChEKEQoRChETA3gDQtdUROMW1YgsiUgF8Gt0FkXtgbk WukK4L3/+/ayY8So4HBEMVUJzRkoRChEKEQoRChEKEQoRKQTMoBHKEQoRChEKEQoRChEKEQoRChE KEQoRChEDMXLZgx6hxLeooN3l0KtEZ1IseptC1dt+/Rr9qO1aHZ0ke0fV1nEN/+7Abws28pftlDL N69ZcDAstAuFCIWIvEIjl27k4yNvC51R00pTV8dEPJdGPwPfh85evpa+D/UecOoatLtlXTNlLoXe D0RLvqLfhwzgEQoRChEKEQoRChEKEQoRChEKEQoRChEKEZcZeLUzaltygygDL3J65nJ+qCeIty2A dwjMkDIDj8gbwItke7zsquRqD3+zhSJRiFCICBGKfHxMaaF096ER0kUUqwN4pdQF8aa/D71DrRHx 5O+Ol82QQaGag7VGH4nud+pZPOuy34FChEKEQoSbgxIKEQoRChEKEQoRChEKEemEmmY/3rmLDo28 6HXHy2Zk310KjSQIjPJLqKeLpgqRyOe/Tw3g7Vz6fjAcwIsm3X3oMiVw16AxbwtlQSFCIeJSaFdm 8GVK4C6e02Wl1L2kLU8JPDvoDJGDX+9Dr9ereVvmSC4z8GqIjpVdCtUcbNZV2f0KO4tnXfY7UIhQ iFCIaFqMcsWy5O0dKEQoRChEKEQoRChEKESkE6reA2/VxPpwBl40KLR6rnF4CXw0VS/5K2dAsMtS TccYwCsKMQoRChEKEQoRChEKEemETDQhFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiwjLwokiXgXfa ZTsz8H4JnR3gWMp81RrTyo5dyZzJzZLqjpdtjUqvZGhh5YxWSheV7srrmEn3zkqzTurbfYNqWyZS rnojoxVl65qEfvzRxAdu131o5t266ll2xdT70PvlvXOj0L+VozhDGh8dZ9l3VzIR5xTuCVzLtIqV PVl1SypW1tRkWL7z9qyD3pHujVEhQiFCIUIhQiFCIUIhQiFCIeJ24nz7lN47u6Se0WU7UYj4V0p9 bOxg5mg2XQulE/pXCpfHTJXwthqFCIUIhQiFCIUIhQiFiOqaDSkrVq4Qe06XXUUWZ7/OGsAjFCIU IhQiFCIUIhQiFCIUIhQiFCIUIhQiqkto3hEZPUrXQgoRChEKEQoRChEKEQoRuYV6drWdXgCghRmh quoiEncV4SM5TXg74wjezV591RRR7P29FpoDeGc/25K8vYrc96EMKEQoRChEKEQoRChEKEQoRChE KEQoRKQTOs3AaxnMRk8+/O/sQ1LWsNpF6AxaaGG2LN0W1mXTaljVMqsFh6eFownpsu2bpaeYFl4F ttCqSpUHzV22JfNlZ7dVJyudsXwm/5MV96XnPu1TbFL8mP1cLSLxTvr8su0ZeCsk3nneObQahQiF CIUIhQiFCIUIhQiFCIUIhQiFiHRC3QG81r+p3XDktIVWTN1dfYHTiCKxdCa/lyVbzs3irkcuI4qR tLTeZQtdfcj7vy/fcq6VKZthtRK9pc9tiPOTnhZo/ZvbFloh8El3l/WkUdT8XnesYxZdMdfac63n SwzHXKNZttSi9jyrirmubKVpsY7eLxH66Ji6sWPkg7Pls5paaEVUKPwFLWSV3kya39fNwAMUIhQi FCIUIhQiFCIUIhQiFCIUIhQiFCIu98DrCeLV/t0dl/Gy1o36ImS+hSI+bEk6V01EKJqmWMcVU7On aAZ2Sw2rK7YlmtTOU29NxUmRaLKDrswXE012kvtO3XLQJZnAd6yaX69aP3TIrAjs/RJqPcjyEpqf rTK7634I1X7bmV2XN0ex9eE5q5X+F/lhEZ9jAI9QiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIjIWUKT DrKSrgy8gyVTeiNMXQK/i8uYa/p5amJ7Tc9Z3AaBa2Md20toziS/0KPC5CuoCpOvpKqFrlL80mcC R7AknauF7rRSVzaUYk3PUsrTuqyUzUHgMx6bmhzFs9JKU1WBT7+TwKqb5Heh2rsW+U8Xqr0t5bvj WfYtlGWBQ7ouU4hQiFCIUIhQiFCIUIhIJ1T1Tl3L344GZaH7nXrWFF9XC6UqMjore/Ng+Bz6b6YE njG7qw66u2zrxPmqWfxSnjbpueq8eec5k56p5hh3dNVBVZdtnWNceYmf0ZXwNpPL/LJSNk96ntHT YukrVraSTsh5akIhQiFCIUIhQiFCIUIhomsGbeZgoGqT4kNkBSi0emhU3UIHW2c/doxin3OV7Rrj P6eFdqEQoRChEPEMoe1ppcTKyawfrx8ZpoUvawsfbJk431Eq84rbOmg7uvBXHbTdM/qYo7iaqpTA 1Du8zUYhQiFCIUIhYmhB0wyem5q8iqZM4BSL4s6kti+sTJmB93q9LgtnbxE6SLUGbQUKEQoRChEK EemEbmfQHlOIZCYKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRChEKEQoRP+YYdy9mKiVhCylE KEQoRChEfC/OzbCWupSTuh+7xXKuyX9faHKQorpOBqmcV9k7u1spfwvtRiFCIUIh4plC2zNf0u/O Vcq6l7fmFedbly/vyMxrKpFA/x7BZRGJXZl4TQu8V1A16ki5BH4VChEKEQoRChG/hFJOWL2ztZRv Bn7NMb6zrZTv7ioE7+Qcdbxn1u2OKn630G6Rg9xXWQYUIhQiFCIUIhQiFCIUIhQiFCIUIhQimmId pcwfUJ4K3U1aHT+rEXv/nNov0j2DNmumDWucv3+zT4m71uoV/lGxsnbCis6vkYmvripfLfHY1ovg dg3aHbOutl9FRrs+JHBKsLlw/xmpdiuNRiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFC IUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCIUIhQiFCISKd0P8DU3MdyMKZsxcAAAAASUVORK5CYII= " + preserveAspectRatio="none" + height="1244.6" + width="9.5249996" + style="display:none" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#fd0000;fill-opacity:0.6350711;stroke:none;stroke-width:0.26458332;stroke-opacity:1" + x="-2.5308407e-06" + y="-873.23492" + id="text4630"><tspan + sodipodi:role="line" + x="-2.5308407e-06" + y="-863.87115" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.58194447px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#fd0000;fill-opacity:0.6350711;stroke:none;stroke-width:0.26458332;stroke-opacity:1" + id="tspan4634" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.26181126px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.20578496" + x="-3.5527137e-15" + y="-272.16272" + id="text4642" + inkscape:export-xdpi="91.400002" + inkscape:export-ydpi="91.400002"><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-263.08344" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.3770504px;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4614" /><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-250.12434" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4658"> ̀</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-237.16527" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4553"> ́</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-224.20619" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4555"> ̂</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-211.24712" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4557"> ̃</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-198.28804" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4559"> ̈</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-185.32896" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4561"> ̊</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-172.36989" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4609"> ̧</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-159.41081" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan8898">ı</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-146.45174" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4565">ß</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-133.49266" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4742">Ø</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-120.53358" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4750">ø</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-107.5745" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4626">Æ</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-94.615425" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4788">æ</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-81.656349" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4792">Ð</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-68.697273" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4796">ð</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-55.738197" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4798">Þ</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-42.779121" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4637">þ</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-29.820045" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4767">«</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-16.86097" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4771">»</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="-3.9018936" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4643">¡</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="9.0571823" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4720">¿</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="22.016258" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4775">¢</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="34.975334" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4724">£</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="47.934425" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4726">¤</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="60.893501" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan4654">¥</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="73.852577" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan881">¹</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="86.811653" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan864">²</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="99.770729" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan862">³</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="112.7298" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan866">º</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="125.68888" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan869">ª</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="138.64796" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan871">©</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="151.60704" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan873">®</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="164.56612" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan875">±</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="177.52519" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan877">×</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="190.48427" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan879">÷</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="203.44334" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan886">¼</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="216.40242" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan888">½</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="229.3615" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan890">¾</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="242.32057" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan882">µ</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="255.27965" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan892">¶</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="268.23871" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan896">¦</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="281.19778" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan898">§</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="294.15686" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan900">¬</tspan><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="306.98413" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan868" /><tspan + sodipodi:role="line" + x="-3.5527137e-15" + y="319.8114" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.93611145px;line-height:1.16499996;font-family:sans-serif;-inkscape-font-specification:sans-serif;fill:#000000;fill-opacity:1;stroke-width:0.20578496" + id="tspan860" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332" + x="0" + y="-1286.5312" + id="text5550"><tspan + sodipodi:role="line" + id="tspan5548" + x="0" + y="-1277.1675" + style="stroke-width:0.26458332" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332" + x="0" + y="-1286.5312" + id="text8872"><tspan + sodipodi:role="line" + id="tspan8870" + x="0" + y="-1277.1675" + style="stroke-width:0.26458332" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332" + x="0" + y="-1269.8625" + id="text8876"><tspan + sodipodi:role="line" + id="tspan8874" + x="0" + y="-1260.4988" + style="stroke-width:0.26458332" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332" + x="0" + y="196.98749" + id="text4641"><tspan + sodipodi:role="line" + id="tspan4639" + x="0" + y="206.35126" + style="stroke-width:0.26458332" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332" + x="0" + y="230.325" + id="text4649"><tspan + sodipodi:role="line" + id="tspan4647" + x="0" + y="239.68877" + style="stroke-width:0.26458332" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332" + x="0" + y="10.456248" + id="text4532"><tspan + sodipodi:role="line" + id="tspan4530" + x="0" + y="19.820017" + style="stroke-width:0.26458332" /></text> + </g> +</svg> diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.cpp new file mode 100644 index 0000000..0e251f7 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/font_size_t.h new file mode 100644 index 0000000..a2cb8b2 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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<typename T> 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.cpp new file mode 100644 index 0000000..d12bf97 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/standard_char_set.h new file mode 100644 index 0000000..48794d4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp new file mode 100644 index 0000000..39b8759 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.cpp @@ -0,0 +1,238 @@ +/*************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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(progmem_str _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(const char *&c) { + utf8_char_t val = *(uint8_t*)c++; + while ((*c & 0xC0) == 0x80) + val = (val << 8) | *(uint8_t*)c++; + return val; + } + + utf8_char_t FTDI::get_utf8_char_and_inc(char *&c) { + utf8_char_t val = *(uint8_t*)c++; + 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) { + const int start_x = x; + while (*str) { + 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) { + #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); + } + + /** + * 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) { + return render_utf8_text(nullptr, 0, 0, str, fs); + } + + uint16_t FTDI::get_utf8_text_width(progmem_str pstr, font_size_t fs) { + char str[strlen_P((const char*)pstr) + 1]; + strcpy_P(str, (const char*)pstr); + return get_utf8_text_width(str, fs); + } + + /** + * 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) + * + */ + + void FTDI::draw_utf8_text(CommandProcessor& cmd, int x, int y, const char *str, font_size_t fs, uint16_t options) { + 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) / 2; + else if (options & OPT_RIGHTX) + x -= get_utf8_text_width(str, fs); + if (options & OPT_CENTERY) + y -= fs.get_height()/2; + + // Render the text + render_utf8_text(&cmd, x, y, str, fs); + cmd.cmd(RESTORE_CONTEXT()); + } + + void FTDI::draw_utf8_text(CommandProcessor& cmd, int x, int y, progmem_str pstr, font_size_t fs, uint16_t options) { + char str[strlen_P((const char*)pstr) + 1]; + strcpy_P(str, (const char*)pstr); + draw_utf8_text(cmd, x, y, (const char*) str, fs, options); + } + +#endif // FTDI_EXTENDED && TOUCH_UI_USE_UTF8 diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/unicode.h new file mode 100644 index 0000000..5bb87d9 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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(progmem_str 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(progmem_str, font_size_t); + uint16_t get_utf8_text_width(const char *, font_size_t); + + void draw_utf8_text(CommandProcessor&, int x, int y, progmem_str, 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); + + // 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.cpp new file mode 100644 index 0000000..4fb2f8f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set.h new file mode 100644 index 0000000..683093d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extended/unicode/western_char_set_bitmap_31.h b/Marlin/src/lcd/extui/lib/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/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/bitmap2cpp.py b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/bitmap2cpp.py new file mode 100644 index 0000000..0c4499e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/bitmap2cpp.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: <https://www.gnu.org/licenses/>. + +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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/circular_progress.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/circular_progress.h new file mode 100644 index 0000000..6695134 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/circular_progress.h @@ -0,0 +1,105 @@ +/*********************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +/* This function draws a circular progress "ring" */ + +void draw_circular_progress(CommandProcessor& cmd, int x, int y, int w, int h, float percent, char *text, uint32_t bgcolor, uint32_t fgcolor) { + using namespace FTDI; + + 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); +} diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/poly_ui.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/poly_ui.h new file mode 100644 index 0000000..ba41650 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#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 POLY_READER> +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 POLY_READER=DeduplicatedPolyReader<TransformedPolyReader>> +class GenericPolyUI { + private: + CommandProcessor &cmd; + + // 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; + + draw_mode_t mode; + + 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 alloted 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/svg2cpp.py b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/svg2cpp.py new file mode 100644 index 0000000..c6eba39 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/extras/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: <https://www.gnu.org/licenses/>. + +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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/** + * 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('<svg[^>]+>', svg); + if s: + m = re.search('viewBox="([0-9-.]+) ([0-9-.]+) ([0-9-.]+) ([0-9-.]+)"', svg) + if m: + self.x_min = float(m.group(1)) + self.y_min = float(m.group(2)) + self.x_max = float(m.group(3)) + self.y_max = float(m.group(4)) + return True + return False + +# op +class WriteDataStructure: + def __init__(self, bounding_box): + self.bounds = bounding_box + + def reset(self, ): + self.hex_words = [] + + def push(self, value): + self.hex_words.append("0x%04X" % (0xFFFF & int(value))) + + def command(self, type, x, y): + if type == "M": + self.push(0xFFFF) + x, y = self.bounds.scale(x,y) + self.push(x * 0xFFFE) + self.push(y * 0xFFFE) + + def path_finished(self, id): + if self.hex_words and self.hex_words[0] == "0xFFFF": + self.hex_words.pop(0) + print("const PROGMEM uint16_t", id + "[] = {" + ", ".join (self.hex_words) + "};") + self.hex_words = [] + +class Parser: + def __init__(self, op): + self.op = op + self.reset() + + def reset(self): + self.last_x = 0 + self.last_y = 0 + self.initial_x = 0 + self.initial_y = 0 + + def process_svg_path_L_or_M(self, cmd, x, y): + self.op.command(cmd, x, y) + self.last_x = x + self.last_y = y + if cmd == "M": + self.initial_x = x + self.initial_y = y + + def process_svg_path_data_cmd(self, id, cmd, a, b): + """Converts the various types of moves into L or M commands + and dispatches to process_svg_path_L_or_M for futher processing.""" + if cmd == "Z" or cmd == "z": + self.process_svg_path_L_or_M("L", self.initial_x, self.initial_y) + elif cmd == "H": + self.process_svg_path_L_or_M("L", a, self.last_y) + elif cmd == "V": + self.process_svg_path_L_or_M("L", self.last_x, a) + elif cmd == "h": + self.process_svg_path_L_or_M("L", self.last_x + a, self.last_y) + elif cmd == "v": + self.process_svg_path_L_or_M("L", self.last_x, self.last_y + a) + elif cmd == "L": + self.process_svg_path_L_or_M("L", a, b) + elif cmd == "l": + self.process_svg_path_L_or_M("L", self.last_x + a, self.last_y + b) + elif cmd == "M": + self.process_svg_path_L_or_M("M", a, b) + elif cmd == "m": + self.process_svg_path_L_or_M("M", self.last_x + a, self.last_y + b) + else: + print("Unsupported path data command:", cmd, "in path", id, "\n", file=sys.stderr) + quit() + + def eat_token(self, regex): + """Looks for a token at the start of self.d. + If found, the token is removed.""" + self.m = re.match(regex,self.d) + if self.m: + self.d = self.d[self.m.end():] + return self.m + + def process_svg_path_data(self, id, d): + """Breaks up the "d" attribute into individual commands + and calls "process_svg_path_data_cmd" for each""" + + self.d = d + while (self.d): + if self.eat_token('\s+'): + pass # Just eat the spaces + + elif self.eat_token('([LMHVZlmhvz])'): + cmd = self.m.group(1) + # The following commands take no arguments + if cmd == "Z" or cmd == "z": + self.process_svg_path_data_cmd(id, cmd, 0, 0) + + elif self.eat_token('([CScsQqTtAa])'): + print("Unsupported path data command:", self.m.group(1), "in path", id, "\n", file=sys.stderr) + quit() + + elif self.eat_token('([ ,]*[-0-9e.]+)+'): + # Process list of coordinates following command + coords = re.split('[ ,]+', self.m.group(0)) + # The following commands take two arguments + if cmd == "L" or cmd == "l": + while coords: + self.process_svg_path_data_cmd(id, cmd, float(coords.pop(0)), float(coords.pop(0))) + elif cmd == "M": + while coords: + self.process_svg_path_data_cmd(id, cmd, float(coords.pop(0)), float(coords.pop(0))) + # If a MOVETO has multiple points, the subsequent ones are assumed to be LINETO + cmd = "L" + elif cmd == "m": + while coords: + self.process_svg_path_data_cmd(id, cmd, float(coords.pop(0)), float(coords.pop(0))) + # If a MOVETO has multiple points, the subsequent ones are assumed to be LINETO + cmd = "l" + # Assume all other commands are single argument + else: + while coords: + self.process_svg_path_data_cmd(id, cmd, float(coords.pop(0)), 0) + else: + print("Syntax error:", d, "in path", id, "\n", file=sys.stderr) + quit() + + def process_svg_paths(self, svg): + self.op.reset() + for path in re.findall('<path[^>]+>', svg): + id = "<none>" + m = re.search(' id="(.*)"', path) + if m: + id = m.group(1) + + m = re.search(' transform="(.*)"', path) + if m: + print("Found transform in path", id, "! Cannot process file!", file=sys.stderr) + quit() + + m = re.search(' d="(.*)"', path) + if m: + self.process_svg_path_data(id, m.group(1)) + self.op.path_finished(id) + self.reset() + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("filename") + args = parser.parse_args() + + f = open(args.filename, "r") + data = f.read() + + print(header) + + b = ComputeBoundingBox() + if not b.from_svg_view_box(data): + # Can't find the view box, so use the bounding box of the elements themselves. + p = Parser(b) + p.process_svg_paths(data) + b.write() + + w = WriteDataStructure(b) + p = Parser(w) + p.process_svg_paths(data) diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/ftdi_eve_lib.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/ftdi_eve_lib/ftdi_eve_lib.h new file mode 100644 index 0000000..c5ddbb4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +#include "compat.h" +#include "basic/ftdi_basic.h" +#include "extended/ftdi_extended.h" diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.cpp new file mode 100644 index 0000000..e4ecdc8 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.cpp @@ -0,0 +1,27 @@ +/**************** + * language.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + + +#include "../../../../../MarlinCore.h" + +#include "language.h" + +uint8_t lang = 0; diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.h new file mode 100644 index 0000000..cbc05c5 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language.h @@ -0,0 +1,23 @@ +/************** + * language.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ +#pragma once + +#include "language_en.h" diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language_en.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language_en.h new file mode 100644 index 0000000..c898e7b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/language/language_en.h @@ -0,0 +1,176 @@ +/***************** + * language_en.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +#include "language.h" + +#if ENABLED(TOUCH_UI_UTF8_COPYRIGHT) + #define COPYRIGHT_SIGN u8"©" +#else + #define COPYRIGHT_SIGN u8"(c)" +#endif + +#if ENABLED(TOUCH_UI_UTF8_WESTERN_CHARSET) + #define DEGREE_SIGN u8"°" +#else + #define DEGREE_SIGN u8" " +#endif + +namespace Language_en { + PROGMEM Language_Str MSG_BUTTON_OKAY = u8"Okay"; + PROGMEM Language_Str MSG_BUTTON_MENU = u8"Menu"; + PROGMEM Language_Str MSG_BUTTON_MEDIA = u8"Media"; + PROGMEM Language_Str MSG_BUTTON_OPEN = u8"Open"; + PROGMEM Language_Str MSG_CLEAN_NOZZLE = u8"Clean Nozzle"; + PROGMEM Language_Str MSG_VMAX_X = u8"Vmax X"; + PROGMEM Language_Str MSG_VMAX_Y = u8"Vmax Y"; + PROGMEM Language_Str MSG_VMAX_Z = u8"Vmax Z"; + PROGMEM Language_Str MSG_ACCEL_PRINTING = u8"Printing"; + PROGMEM Language_Str MSG_ACCEL_TRAVEL = u8"Travel"; + PROGMEM Language_Str MSG_ACCEL_RETRACT = u8"Retraction"; + PROGMEM Language_Str MSG_AMAX_X = u8"Amax X"; + PROGMEM Language_Str MSG_AMAX_Y = u8"Amax Y"; + PROGMEM Language_Str MSG_AMAX_Z = u8"Amax Z"; + PROGMEM Language_Str MSG_AXIS_X = u8"X"; + PROGMEM Language_Str MSG_AXIS_X2 = u8"X2"; + PROGMEM Language_Str MSG_AXIS_Y = u8"Y"; + PROGMEM Language_Str MSG_AXIS_Y2 = u8"Y2"; + PROGMEM Language_Str MSG_AXIS_Z = u8"Z"; + PROGMEM Language_Str MSG_AXIS_Z2 = u8"Z2"; + PROGMEM Language_Str MSG_AXIS_E = u8"E"; + PROGMEM Language_Str MSG_AXIS_E1 = u8"E1"; + PROGMEM Language_Str MSG_AXIS_E2 = u8"E2"; + PROGMEM Language_Str MSG_AXIS_E3 = u8"E3"; + PROGMEM Language_Str MSG_AXIS_E4 = u8"E4"; + PROGMEM Language_Str MSG_AXIS_ALL = u8"All"; + PROGMEM Language_Str MSG_HOME = u8"Home"; + PROGMEM Language_Str MSG_PRINT_STARTING = u8"Print starting"; + PROGMEM Language_Str MSG_PRINT_FINISHED = u8"Print finished"; + PROGMEM Language_Str MSG_PRINT_ERROR = u8"Print error"; + PROGMEM Language_Str MSG_ABOUT_TOUCH_PANEL_1 = u8"Color Touch Panel"; + PROGMEM Language_Str MSG_ABOUT_TOUCH_PANEL_2 = WEBSITE_URL; + PROGMEM Language_Str MSG_LICENSE = u8"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.\n\nTo view a copy of the GNU General " + "Public License, go to the following location: https://www.gnu.org/licenses."; + PROGMEM Language_Str MSG_RUNOUT_1 = u8"Runout 1"; + PROGMEM Language_Str MSG_RUNOUT_2 = u8"Runout 2"; + PROGMEM Language_Str MSG_DISPLAY_MENU = u8"Display"; + PROGMEM Language_Str MSG_INTERFACE = u8"Interface"; + PROGMEM Language_Str MSG_MEASURE_AUTOMATICALLY = u8"Measure automatically"; + PROGMEM Language_Str MSG_H_OFFSET = u8"H Offset"; + PROGMEM Language_Str MSG_V_OFFSET = u8"V Offset"; + PROGMEM Language_Str MSG_TOUCH_SCREEN = u8"Touch Screen"; + PROGMEM Language_Str MSG_CALIBRATE = u8"Calibrate"; + PROGMEM Language_Str MSG_UNITS_MILLIAMP = u8"mA"; + PROGMEM Language_Str MSG_UNITS_MM = u8"mm"; + PROGMEM Language_Str MSG_UNITS_MM_S = u8"mm/s"; + PROGMEM Language_Str MSG_UNITS_MM_S2 = u8"mm/s" SUPERSCRIPT_TWO; + PROGMEM Language_Str MSG_UNITS_STEP_MM = u8"st/mm"; + PROGMEM Language_Str MSG_UNITS_PERCENT = u8"%"; + PROGMEM Language_Str MSG_UNITS_C = DEGREE_SIGN u8"C"; + PROGMEM Language_Str MSG_IDLE = u8"idle"; + PROGMEM Language_Str MSG_SET_MAXIMUM = u8"Set Maximum"; + PROGMEM Language_Str MSG_PRINT_SPEED = u8"Print Speed"; + PROGMEM Language_Str MSG_LINEAR_ADVANCE = u8"Linear Advance"; + PROGMEM Language_Str MSG_LINEAR_ADVANCE_K = u8"K"; + PROGMEM Language_Str MSG_LINEAR_ADVANCE_K1 = u8"K E1"; + PROGMEM Language_Str MSG_LINEAR_ADVANCE_K2 = u8"K E2"; + PROGMEM Language_Str MSG_LINEAR_ADVANCE_K3 = u8"K E3"; + PROGMEM Language_Str MSG_LINEAR_ADVANCE_K4 = u8"K E4"; + PROGMEM Language_Str MSG_NUDGE_NOZZLE = u8"Nudge Nozzle"; + PROGMEM Language_Str MSG_ADJUST_BOTH_NOZZLES = u8"Adjust Both Nozzles"; + PROGMEM Language_Str MSG_SHOW_OFFSETS = u8"Show Offsets"; + PROGMEM Language_Str MSG_INCREMENT = u8"Increment"; + PROGMEM Language_Str MSG_ERASE_FLASH_WARNING = u8"Are you sure? SPI flash will be erased."; + PROGMEM Language_Str MSG_ERASING = u8"Erasing..."; + PROGMEM Language_Str MSG_ERASED = u8"SPI flash erased"; + PROGMEM Language_Str MSG_CALIBRATION_WARNING = u8"For best results, unload the filament and clean the hotend prior to starting calibration. Continue?"; + PROGMEM Language_Str MSG_START_PRINT_CONFIRMATION = u8"Start printing %s?"; + PROGMEM Language_Str MSG_ABORT_WARNING = u8"Are you sure you want to cancel the print?"; + PROGMEM Language_Str MSG_EXTRUDER_SELECTION = u8"Extruder Selection"; + PROGMEM Language_Str MSG_CURRENT_TEMPERATURE = u8"Current Temp"; + PROGMEM Language_Str MSG_REMOVAL_TEMPERATURE = u8"Removal Temp"; + PROGMEM Language_Str MSG_CAUTION = u8"Caution:"; + PROGMEM Language_Str MSG_HOT = u8"Hot!"; + PROGMEM Language_Str MSG_UNLOAD_FILAMENT = u8"Unload/Retract"; + PROGMEM Language_Str MSG_LOAD_FILAMENT = u8"Load/Extrude"; + PROGMEM Language_Str MSG_MOMENTARY = u8"Momentary"; + PROGMEM Language_Str MSG_CONTINUOUS = u8"Continuous"; + PROGMEM Language_Str MSG_PLEASE_WAIT = u8"Please wait..."; + PROGMEM Language_Str MSG_PRINT_MENU = u8"Print Menu"; + PROGMEM Language_Str MSG_FINE_MOTION = u8"Fine motion"; + PROGMEM Language_Str MSG_ENABLE_MEDIA = u8"Enable Media"; + PROGMEM Language_Str MSG_INSERT_MEDIA = u8"Insert Media..."; + PROGMEM Language_Str MSG_LCD_BRIGHTNESS = u8"LCD brightness"; + PROGMEM Language_Str MSG_SOUND_VOLUME = u8"Sound volume"; + PROGMEM Language_Str MSG_SCREEN_LOCK = u8"Screen lock"; + PROGMEM Language_Str MSG_BOOT_SCREEN = u8"Boot screen"; + PROGMEM Language_Str MSG_SOUNDS = u8"Sounds"; + PROGMEM Language_Str MSG_CLICK_SOUNDS = u8"Click sounds"; + PROGMEM Language_Str MSG_EEPROM_RESTORED = u8"Settings restored from backup"; + PROGMEM Language_Str MSG_EEPROM_RESET = u8"Settings restored to default"; + PROGMEM Language_Str MSG_EEPROM_SAVED = u8"Settings saved!"; + PROGMEM Language_Str MSG_EEPROM_SAVE_PROMPT = u8"Do you wish to save these settings as defaults?"; + PROGMEM Language_Str MSG_EEPROM_RESET_WARNING = u8"Are you sure? Customizations will be lost."; + + PROGMEM Language_Str MSG_PASSCODE_REJECTED = u8"Wrong passcode!"; + PROGMEM Language_Str MSG_PASSCODE_ACCEPTED = u8"Passcode accepted!"; + PROGMEM Language_Str MSG_PASSCODE_SELECT = u8"Select Passcode:"; + PROGMEM Language_Str MSG_PASSCODE_REQUEST = u8"Enter Passcode:"; + + PROGMEM Language_Str MSG_TOUCH_CALIBRATION_START = u8"Release to begin screen calibration"; + PROGMEM Language_Str MSG_TOUCH_CALIBRATION_PROMPT = u8"Touch the dots to calibrate"; + PROGMEM Language_Str MSG_AUTOLEVEL_X_AXIS = u8"Level X Axis"; + PROGMEM Language_Str MSG_BED_MAPPING_DONE = u8"Bed mapping finished"; + PROGMEM Language_Str MSG_BED_MAPPING_INCOMPLETE = u8"Not all points probed"; + PROGMEM Language_Str MSG_LEVELING = u8"Leveling"; + PROGMEM Language_Str MSG_SHOW_MESH = u8"Show Bed Mesh"; + + #if ENABLED(TOUCH_UI_LULZBOT_BIO) + PROGMEM Language_Str MSG_MOVE_TO_HOME = u8"Move to Home"; + PROGMEM Language_Str MSG_RAISE_PLUNGER = u8"Raise Plunger"; + PROGMEM Language_Str MSG_RELEASE_XY_AXIS = u8"Release X and Y Axis"; + PROGMEM Language_Str MSG_BED_TEMPERATURE = u8"Bed Temperature"; + PROGMEM Language_Str MSG_HOME_XYZ_WARNING = u8"About to move to home position. Ensure the top and the bed of the printer are clear.\n\nContinue?"; + PROGMEM Language_Str MSG_HOME_E_WARNING = u8"About to re-home plunger and auto-level. Remove syringe prior to proceeding.\n\nContinue?"; + #endif + + #ifdef TOUCH_UI_COCOA_PRESS + PROGMEM Language_Str MSG_BODY = u8"Body"; + PROGMEM Language_Str MSG_INTERNAL = u8"Internal"; + PROGMEM Language_Str MSG_EXTERNAL = u8"External"; + PROGMEM Language_Str MSG_CHOCOLATE = u8"Chocolate"; + PROGMEM Language_Str MSG_UNLOAD_CARTRIDGE = u8"Unload Cartridge"; + PROGMEM Language_Str MSG_LOAD_CHOCOLATE = u8"Load Chocolate"; + PROGMEM Language_Str MSG_CARTRIDGE_IN = u8"Cartridge In"; + PROGMEM Language_Str MSG_CARTRIDGE_OUT = u8"Cartridge Out"; + PROGMEM Language_Str MSG_PREHEAT_CHOCOLATE = u8"Preheat Chocolate"; + PROGMEM Language_Str MSG_PREHEAT_FINISHED = u8"Preheat finished"; + PROGMEM Language_Str MSG_PREHEAT = u8"Preheat"; + PROGMEM Language_Str MSG_BUTTON_PAUSE = u8"Pause"; + PROGMEM Language_Str MSG_BUTTON_RESUME = u8"Resume"; + PROGMEM Language_Str MSG_ELAPSED_PRINT = u8"Elapsed Print"; + PROGMEM Language_Str MSG_XYZ_MOVE = u8"XYZ Move"; + PROGMEM Language_Str MSG_E_MOVE = u8"Extrusion Move"; + #endif +}; // namespace Language_en diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/marlin_events.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/marlin_events.cpp new file mode 100644 index 0000000..fc9b5d0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/marlin_events.cpp @@ -0,0 +1,184 @@ +/********************* + * marlin_events.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "compat.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens/screens.h" + +namespace ExtUI { + using namespace Theme; + using namespace FTDI; + + void onStartup() { + EventLoop::setup(); + } + + void onIdle() { + EventLoop::loop(); + } + + void onPrinterKilled(PGM_P const error, PGM_P const component) { + char str[strlen_P(error) + strlen_P(component) + 3]; + sprintf_P(str, PSTR(S_FMT ": " S_FMT), error, component); + KillScreen::show(str); + } + + void onMediaInserted() { + if (AT_SCREEN(StatusScreen)) + StatusScreen::setStatusMessage(GET_TEXT_F(MSG_MEDIA_INSERTED)); + sound.play(media_inserted, PLAY_ASYNCHRONOUS); + } + + void onMediaRemoved() { + if (isPrintingFromMedia()) { + stopPrint(); + InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FAILED); + } + else + sound.play(media_removed, PLAY_ASYNCHRONOUS); + + if (AT_SCREEN(StatusScreen) || isPrintingFromMedia()) + StatusScreen::setStatusMessage(GET_TEXT_F(MSG_MEDIA_REMOVED)); + + #if ENABLED(SDSUPPORT) + if (AT_SCREEN(FilesScreen)) GOTO_SCREEN(StatusScreen); + #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 onStatusChanged(progmem_str lcd_msg) { + StatusScreen::setStatusMessage(lcd_msg); + } + + void onPrintTimerStarted() { + InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_STARTED); + } + + void onPrintTimerStopped() { + InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FINISHED); + } + + void onPrintTimerPaused() {} + + void onPrintFinished() {} + + 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 onHomingComplete() {} + + void onFactoryReset() { + InterfaceSettingsScreen::defaultSettings(); + } + + void onStoreSettings(char *buff) { + InterfaceSettingsScreen::saveSettings(buff); + } + + void onLoadSettings(const char *buff) { + InterfaceSettingsScreen::loadSettings(buff); + } + + void onConfigurationStoreWritten(bool success) { + #ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE + if (success && InterfaceSettingsScreen::backupEEPROM()) { + SERIAL_ECHOLNPGM("Made backup of EEPROM to SPI Flash"); + } + #else + UNUSED(success); + #endif + } + + void onConfigurationStoreRead(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 onMeshLevelingStart() {} + + void onMeshUpdate(const int8_t x, const int8_t y, const float val) { + BedMeshScreen::onMeshUpdate(x, y, val); + } + + void onMeshUpdate(const int8_t x, const int8_t y, const ExtUI::probe_state_t state) { + BedMeshScreen::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_ECHOLNPAIR("OnPidTuning:", rst); + switch (rst) { + 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/pin_mappings.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/pin_mappings.h new file mode 100644 index 0000000..ae95a64 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/pin_mappings.h @@ -0,0 +1,144 @@ +/****************** + * pin_mappings.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +/* This file defines mappings from the ULTRA_LCD pins functions to new + * functions for the FTDI display. These mappings allows any board that + * support ULTRA_LCD via EXP1 and EXP2 connectors to use FTDI modules + * without adding new pin definitions to the board. + */ + +#include "../../../../inc/MarlinConfig.h" + +#if ENABLED(F6_TFT_PINMAP) // FYSETC F6 - ATmega2560 + + #define CLCD_SPI_CS 33 + #define CLCD_MOD_RESET 31 + +#elif ENABLED(S6_TFT_PINMAP) // FYSETC S6 - STM32F4 + + #define CLCD_SPI_CS PC7 + #define CLCD_MOD_RESET PC6 + +#elif ENABLED(CR10_TFT_PINMAP) // FYSETC S6 - STM32F4 - with TOUCH_UI_ULTIPANEL + + #define CLCD_USE_SOFT_SPI + #define CLCD_SOFT_SPI_SCLK LCD_PINS_D4 // PORTA1 Pin 6 + #define CLCD_SOFT_SPI_MOSI LCD_PINS_ENABLE // PORTC1 Pin 8 + #define CLCD_SPI_CS LCD_PINS_RS // PORTA3 Pin 7 + #define CLCD_SOFT_SPI_MISO 16 // PORTC0 BTN_ENC Pin 2 + #define CLCD_MOD_RESET 11 // PORTD3 BTN_EN1 Pin 3 + #define CLCD_AUX_0 10 // PORTD2 BTN_EN2 Pin 5 + #define CLCD_AUX_1 BEEPER_PIN // PORTA4 Pin 1 + +#elif ENABLED(AO_EXP1_DEPRECATED_PINMAP) + + /** + * This AlephObjects pinout re-purposes the UltraLCD + * connector EXP1 for Software SPI (rev B, obsolete) + */ + + #define CLCD_MOD_RESET LCD_PINS_D4 + #define CLCD_SPI_CS LCD_PINS_D5 + + #define CLCD_AUX_0 LCD_PINS_ENABLE + #define CLCD_AUX_1 BTN_ENC + #define CLCD_AUX_2 BEEPER_PIN + + #define CLCD_USE_SOFT_SPI + #define CLCD_SOFT_SPI_SCLK LCD_PINS_D7 + #define CLCD_SOFT_SPI_MOSI LCD_PINS_D6 + #define CLCD_SOFT_SPI_MISO LCD_PINS_RS + +#elif ENABLED(AO_EXP1_PINMAP) + + /** + * AO_EXP1_PINMAP with TOUCH_UI_ULTIPANEL + * + * This AlephObjects mapping re-purposes the UltraLCD + * connector EXP1 for Software SPI for display (rev C): + * + * EXP2: FTDI: SD -or- USB [1]: ULTRA_LCD: + * 1 MISO MISO MISO --> BEEPER + * 2 SCLK SCLK SCLK --> BTN_ENC + * 3 PD_N - - --> LCDE + * 4 - CS_N CS_N --> LCDRS + * 5 CS_N - - --> LCD4 + * 6 MOSI MOSI MOSI --> LCD5 + * 7 - SD_DET INT --> LCD6 + * 8 RESET - RESET --> LCD4 + * 9 GND GND GND --> GND + * 10 5V 5V 5V --> 5V + * + * [1] At the moment, Marlin does not support SD or USB + * functionality over software SPI. + */ + + #define CLCD_MOD_RESET LCD_PINS_ENABLE + #define CLCD_SPI_CS LCD_PINS_D4 + + #define CLCD_USE_SOFT_SPI + #define CLCD_SOFT_SPI_SCLK BTN_ENC + #define CLCD_SOFT_SPI_MOSI LCD_PINS_D5 + #define CLCD_SOFT_SPI_MISO BEEPER_PIN + +#elif ENABLED(AO_EXP2_PINMAP) + + /** + * AO_EXP2_PINMAP with TOUCH_UI_ULTIPANEL + * + * The AlephObjects mapping for re-purposing the UltraLCD + * connector EXP2 for hardware SPI for display and SD card + * or USB (rev C): + * + * EXP2: FTDI: SD -or- USB: ULTRA_LCD: + * 1 MISO MISO MISO --> MISO + * 2 SCLK SCLK SCLK --> SCLK + * 3 PD_N - - --> BTN_EN2 + * 4 - CS_N CS_N --> SD_CSEL + * 5 CS_N - - --> BTN_EN1 + * 6 MOSI MOSI MOSI --> MOSI + * 7 - SD_DET INT --> SD_DET + * 8 RESET - RESET --> RESET + * 9 GND GND GND --> GND + * 10 5V 5V 5V --> KILL [3] + * + * [1] This configuration allows daisy-chaining of the + * display and SD/USB on EXP2, except for [2] + * + * [2] The Ultimachine Einsy boards have a level shifter + * on MISO enabled by SD_CSEL chip select, hence it + * is not possible to run both the display and the + * SD/USB on EXP2. + * + * [3] Archim Rambo provides 5V on this pin. On any other + * board, divert this wire from the ribbon cable and + * connect it to 5V at an endstop. + */ + + #define CLCD_SPI_CS BTN_EN1 + #define CLCD_MOD_RESET BTN_EN2 + #if MB(EINSY_RAMBO, EINSY_RETRO) && DISABLED(SDSUPPORT) + #define CLCD_SPI_EXTRA_CS SDSS + #endif + +#endif diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/about_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/about_screen.cpp new file mode 100644 index 0000000..952f0ca --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/about_screen.cpp @@ -0,0 +1,116 @@ +/******************** + * about_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +#define GRID_COLS 4 +#define GRID_ROWS 7 + +using namespace FTDI; +using namespace Theme; +using namespace ExtUI; + +void AboutScreen::onEntry() { + BaseScreen::onEntry(); + sound.play(chimes, PLAY_ASYNCHRONOUS); +} + +void AboutScreen::onRedraw(draw_mode_t) { + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0); + + #define HEADING_POS BTN_POS(1,2), BTN_SIZE(4,1) + #define FW_VERS_POS BTN_POS(1,3), BTN_SIZE(4,1) + #define FW_INFO_POS BTN_POS(1,4), BTN_SIZE(4,1) + #define LICENSE_POS BTN_POS(1,5), BTN_SIZE(4,2) + #define STATS_POS BTN_POS(1,7), BTN_SIZE(2,1) + #define BACK_POS BTN_POS(3,7), BTN_SIZE(2,1) + + #define _INSET_POS(x,y,w,h) x + w/10, y, w - w/5, h + #define INSET_POS(pos) _INSET_POS(pos) + + char about_str[1 + + strlen_P(GET_TEXT(MSG_ABOUT_TOUCH_PANEL_2)) + #ifdef TOOLHEAD_NAME + + strlen_P(TOOLHEAD_NAME) + #endif + ]; + #ifdef TOOLHEAD_NAME + // If MSG_ABOUT_TOUCH_PANEL_2 has %s, substitute in the toolhead name. + // But this is optional, so squelch the compiler warning here. + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wformat-extra-args" + sprintf_P(about_str, GET_TEXT(MSG_ABOUT_TOUCH_PANEL_2), TOOLHEAD_NAME); + #pragma GCC diagnostic pop + #else + strcpy_P(about_str, GET_TEXT(MSG_ABOUT_TOUCH_PANEL_2)); + #endif + + draw_text_box(cmd, HEADING_POS, + #ifdef CUSTOM_MACHINE_NAME + F(CUSTOM_MACHINE_NAME) + #else + GET_TEXT_F(MSG_ABOUT_TOUCH_PANEL_1) + #endif + , OPT_CENTER, font_xlarge + ); + cmd.tag(3); + draw_text_box(cmd, FW_VERS_POS, + #ifdef TOUCH_UI_VERSION + F(TOUCH_UI_VERSION) + #else + progmem_str(getFirmwareName_str()) + #endif + , OPT_CENTER, font_medium); + cmd.tag(0); + draw_text_box(cmd, FW_INFO_POS, about_str, OPT_CENTER, font_medium); + draw_text_box(cmd, INSET_POS(LICENSE_POS), GET_TEXT_F(MSG_LICENSE), OPT_CENTER, font_tiny); + + cmd.font(font_medium) + .colors(normal_btn) + .tag(2).button(STATS_POS, GET_TEXT_F(MSG_INFO_STATS_MENU)) + .colors(action_btn) + .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK)); +} + +bool AboutScreen::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + #if ENABLED(PRINTCOUNTER) + case 2: GOTO_SCREEN(StatisticsScreen); break; + #endif + #if ENABLED(TOUCH_UI_DEVELOPER_MENU) + case 3: GOTO_SCREEN(DeveloperMenu); break; + #endif + default: return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/advanced_settings_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/advanced_settings_menu.cpp new file mode 100644 index 0000000..9036fc1 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/advanced_settings_menu.cpp @@ -0,0 +1,156 @@ +/***************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) && NONE(TOUCH_UI_LULZBOT_BIO, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +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 ENABLED(TOUCH_UI_PORTRAIT) + #if EITHER(HAS_MULTI_HOTEND, SENSORLESS_HOMING) + #define GRID_ROWS 9 + #else + #define GRID_ROWS 8 + #endif + #define GRID_COLS 2 + #define RESTORE_DEFAULTS_POS BTN_POS(1,1), BTN_SIZE(2,1) + #define DISPLAY_POS BTN_POS(1,2), BTN_SIZE(1,1) + #define INTERFACE_POS BTN_POS(2,2), BTN_SIZE(1,1) + #define ZPROBE_ZOFFSET_POS BTN_POS(1,3), BTN_SIZE(1,1) + #define STEPS_PER_MM_POS BTN_POS(2,3), BTN_SIZE(1,1) + #define FILAMENT_POS BTN_POS(1,4), BTN_SIZE(1,1) + #define VELOCITY_POS BTN_POS(2,4), BTN_SIZE(1,1) + #define TMC_CURRENT_POS BTN_POS(1,5), BTN_SIZE(1,1) + #define ACCELERATION_POS BTN_POS(2,5), BTN_SIZE(1,1) + #define ENDSTOPS_POS BTN_POS(1,6), BTN_SIZE(1,1) + #define JERK_POS BTN_POS(2,6), BTN_SIZE(1,1) + #define CASE_LIGHT_POS BTN_POS(1,7), BTN_SIZE(1,1) + #define BACKLASH_POS BTN_POS(2,7), BTN_SIZE(1,1) + #define OFFSETS_POS BTN_POS(1,8), BTN_SIZE(1,1) + #define TMC_HOMING_THRS_POS BTN_POS(2,8), BTN_SIZE(1,1) + #if EITHER(HAS_MULTI_HOTEND, SENSORLESS_HOMING) + #define BACK_POS BTN_POS(1,9), BTN_SIZE(2,1) + #else + #define BACK_POS BTN_POS(1,8), BTN_SIZE(2,1) + #endif + #else + #define GRID_ROWS 6 + #define GRID_COLS 3 + #define ZPROBE_ZOFFSET_POS BTN_POS(1,1), BTN_SIZE(1,1) + #define CASE_LIGHT_POS BTN_POS(1,4), BTN_SIZE(1,1) + #define STEPS_PER_MM_POS BTN_POS(2,1), BTN_SIZE(1,1) + #define TMC_CURRENT_POS BTN_POS(3,1), BTN_SIZE(1,1) + #define TMC_HOMING_THRS_POS BTN_POS(3,2), BTN_SIZE(1,1) + #define BACKLASH_POS BTN_POS(3,3), BTN_SIZE(1,1) + #define FILAMENT_POS BTN_POS(1,3), BTN_SIZE(1,1) + #define ENDSTOPS_POS BTN_POS(3,4), BTN_SIZE(1,1) + #define DISPLAY_POS BTN_POS(3,5), BTN_SIZE(1,1) + #define INTERFACE_POS BTN_POS(1,5), BTN_SIZE(2,1) + #define RESTORE_DEFAULTS_POS BTN_POS(1,6), BTN_SIZE(2,1) + #define VELOCITY_POS BTN_POS(2,2), BTN_SIZE(1,1) + #define ACCELERATION_POS BTN_POS(2,3), BTN_SIZE(1,1) + #define JERK_POS BTN_POS(2,4), BTN_SIZE(1,1) + #define OFFSETS_POS BTN_POS(1,2), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(3,6), BTN_SIZE(1,1) + #endif + + if (what & FOREGROUND) { + CommandProcessor cmd; + cmd.colors(normal_btn) + .font(Theme::font_medium) + .enabled(ENABLED(HAS_BED_PROBE)) + .tag(2) .button(ZPROBE_ZOFFSET_POS, GET_TEXT_F(MSG_ZPROBE_ZOFFSET)) + .enabled(ENABLED(CASE_LIGHT_ENABLE)) + .tag(16).button(CASE_LIGHT_POS, GET_TEXT_F(MSG_CASE_LIGHT)) + .tag(3) .button(STEPS_PER_MM_POS, GET_TEXT_F(MSG_STEPS_PER_MM)) + .enabled(ENABLED(HAS_TRINAMIC_CONFIG)) + .tag(13).button(TMC_CURRENT_POS, GET_TEXT_F(MSG_TMC_CURRENT)) + .enabled(ENABLED(SENSORLESS_HOMING)) + .tag(14).button(TMC_HOMING_THRS_POS, GET_TEXT_F(MSG_TMC_HOMING_THRS)) + .enabled(ENABLED(HAS_MULTI_HOTEND)) + .tag(4) .button(OFFSETS_POS, GET_TEXT_F(MSG_OFFSETS_MENU)) + .enabled(EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)) + .tag(11).button(FILAMENT_POS, GET_TEXT_F(MSG_FILAMENT)) + .tag(12).button(ENDSTOPS_POS, GET_TEXT_F(MSG_LCD_ENDSTOPS)) + .tag(15).button(DISPLAY_POS, GET_TEXT_F(MSG_DISPLAY_MENU)) + .tag(9) .button(INTERFACE_POS, GET_TEXT_F(MSG_INTERFACE)) + .tag(10).button(RESTORE_DEFAULTS_POS, GET_TEXT_F(MSG_RESTORE_DEFAULTS)) + .tag(5) .button(VELOCITY_POS, GET_TEXT_F(MSG_VELOCITY)) + .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))) + .enabled(ENABLED(BACKLASH_GCODE)) + .tag(8).button(BACKLASH_POS, GET_TEXT_F(MSG_BACKLASH)) + .colors(action_btn) + .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK)); + } +} + +bool AdvancedSettingsMenu::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: SaveSettingsDialogBox::promptToSaveSettings(); break; + #if HAS_BED_PROBE + case 2: GOTO_SCREEN(ZOffsetScreen); break; + #endif + case 3: GOTO_SCREEN(StepsScreen); break; + #if ENABLED(HAS_MULTI_HOTEND) + case 4: GOTO_SCREEN(NozzleOffsetScreen); 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; + #if ENABLED(BACKLASH_GCODE) + case 8: GOTO_SCREEN(BacklashCompensationScreen); break; + #endif + case 9: GOTO_SCREEN(InterfaceSettingsScreen); LockScreen::check_passcode(); break; + case 10: GOTO_SCREEN(RestoreFailsafeDialogBox); LockScreen::check_passcode(); break; + #if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR) + case 11: GOTO_SCREEN(FilamentMenu); break; + #endif + case 12: GOTO_SCREEN(EndstopStatesScreen); break; + #if HAS_TRINAMIC_CONFIG + case 13: GOTO_SCREEN(StepperCurrentScreen); break; + #endif + #if ENABLED(SENSORLESS_HOMING) + case 14: GOTO_SCREEN(StepperBumpSensitivityScreen); break; + #endif + case 15: GOTO_SCREEN(DisplayTuningScreen); break; + #if ENABLED(CASE_LIGHT_ENABLE) + case 16: GOTO_SCREEN(CaseLightScreen); break; + #endif + default: return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE && !TOUCH_UI_LULZBOT_BIO diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/alert_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/alert_dialog_box.cpp new file mode 100644 index 0000000..d63119a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/alert_dialog_box.cpp @@ -0,0 +1,70 @@ +/************************ + * alert_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace Theme; + +void AlertDialogBox::onEntry() { + BaseScreen::onEntry(); + sound.play(screen_data.AlertDialog.isError ? sad_trombone : twinkle, PLAY_ASYNCHRONOUS); +} + +void AlertDialogBox::onRedraw(draw_mode_t what) { + if (what & FOREGROUND) { + drawOkayButton(); + } +} + +template<typename T> +void AlertDialogBox::show(const T message) { + drawMessage(message); + storeBackground(); + screen_data.AlertDialog.isError = false; + GOTO_SCREEN(AlertDialogBox); +} + +template<typename T> +void AlertDialogBox::showError(const T message) { + drawMessage(message); + storeBackground(); + screen_data.AlertDialog.isError = true; + GOTO_SCREEN(AlertDialogBox); +} + +void AlertDialogBox::hide() { + if (AT_SCREEN(AlertDialogBox)) + GOTO_PREVIOUS(); +} + +template void AlertDialogBox::show(const char *); +template void AlertDialogBox::show(const progmem_str); +template void AlertDialogBox::showError(const char *); +template void AlertDialogBox::showError(const progmem_str); + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/backlash_compensation_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/backlash_compensation_screen.cpp new file mode 100644 index 0000000..58f4544 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/backlash_compensation_screen.cpp @@ -0,0 +1,76 @@ +/************************************ + * backlash_compensation_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, BACKLASH_GCODE) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void BacklashCompensationScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(2).units( GET_TEXT_F(MSG_UNITS_MM)); + w.heading( GET_TEXT_F(MSG_BACKLASH)); + w.color(x_axis).adjuster(2, GET_TEXT_F(MSG_AXIS_X), getAxisBacklash_mm(X)); + w.color(y_axis).adjuster(4, GET_TEXT_F(MSG_AXIS_Y), getAxisBacklash_mm(Y)); + w.color(z_axis).adjuster(6, GET_TEXT_F(MSG_AXIS_Z), getAxisBacklash_mm(Z)); + #if ENABLED(CALIBRATION_GCODE) + w.button(12, GET_TEXT_F(MSG_MEASURE_AUTOMATICALLY)); + #endif + #ifdef BACKLASH_SMOOTHING_MM + w.color(other).adjuster(8, GET_TEXT_F(MSG_BACKLASH_SMOOTHING), getBacklashSmoothing_mm()); + #endif + w.precision(0).units(GET_TEXT_F(MSG_UNITS_PERCENT)) + .adjuster(10, GET_TEXT_F(MSG_BACKLASH_CORRECTION), getBacklashCorrection_percent()); + w.precision(2).increments(); +} + +bool BacklashCompensationScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(AxisBacklash_mm, X); break; + case 3: UI_INCREMENT(AxisBacklash_mm, X); break; + case 4: UI_DECREMENT(AxisBacklash_mm, Y); break; + case 5: UI_INCREMENT(AxisBacklash_mm, Y); break; + case 6: UI_DECREMENT(AxisBacklash_mm, Z); break; + case 7: UI_INCREMENT(AxisBacklash_mm, Z); break; + #ifdef BACKLASH_SMOOTHING_MM + case 8: UI_DECREMENT(BacklashSmoothing_mm); break; + case 9: UI_INCREMENT(BacklashSmoothing_mm); break; + #endif + case 10: UI_DECREMENT_BY(BacklashCorrection_percent, increment*100); break; + case 11: UI_INCREMENT_BY(BacklashCorrection_percent, increment*100); break; + #if ENABLED(CALIBRATION_GCODE) + case 12: GOTO_SCREEN(ConfirmAutoCalibrationDialogBox); return true; + #endif + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_numeric_adjustment_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_numeric_adjustment_screen.cpp new file mode 100644 index 0000000..5271df3 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_numeric_adjustment_screen.cpp @@ -0,0 +1,388 @@ +/************************************** + * base_numeric_adjustment_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace Theme; + +#if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_COLS 13 + #define GRID_ROWS 10 + #define LAYOUT_FONT font_small +#else + #define GRID_COLS 18 + #define GRID_ROWS 7 + #define LAYOUT_FONT font_medium +#endif + +BaseNumericAdjustmentScreen::widgets_t::widgets_t(draw_mode_t what) : _what(what) { + CommandProcessor cmd; + + if (what & BACKGROUND) { + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .colors(normal_btn) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0); + } + + cmd.font(font_medium); + _button(cmd, 1, + #if ENABLED(TOUCH_UI_PORTRAIT) + BTN_POS(1,10), BTN_SIZE(13,1), + #else + BTN_POS(15,7), BTN_SIZE(4,1), + #endif + GET_TEXT_F(MSG_BACK), true, true + ); + + _line = 1; + _units = F(""); +} + +/** + * Speed optimization for changing button style. + */ +void BaseNumericAdjustmentScreen::widgets_t::_button_style(CommandProcessor &cmd, BaseNumericAdjustmentScreen::widgets_t::style_t style) { + if (_style != style) { + const btn_colors *old_colors = &normal_btn; + const btn_colors *new_colors = &normal_btn; + + switch (_style) { + case BTN_ACTION: old_colors = &action_btn; break; + case BTN_TOGGLE: old_colors = &ui_toggle; break; + case BTN_DISABLED: old_colors = &disabled_btn; break; + default: break; + } + switch (style) { + case BTN_ACTION: new_colors = &action_btn; break; + case BTN_TOGGLE: new_colors = &ui_toggle; break; + case BTN_DISABLED: new_colors = &disabled_btn; break; + default: break; + } + + const bool rgb_changed = (old_colors->rgb != new_colors->rgb) || + (_style == TEXT_LABEL && style != TEXT_LABEL) || + (_style != TEXT_LABEL && style == TEXT_LABEL); + const bool grad_changed = old_colors->grad != new_colors->grad; + const bool fg_changed = (old_colors->fg != new_colors->fg) || (_style == TEXT_AREA); + const bool bg_changed = old_colors->bg != new_colors->bg; + + if (rgb_changed) cmd.cmd(COLOR_RGB(style == TEXT_LABEL ? bg_text_enabled : new_colors->rgb)); + if (grad_changed) cmd.gradcolor(new_colors->grad); + if (fg_changed) cmd.fgcolor(new_colors->fg); + if (bg_changed) cmd.bgcolor(new_colors->bg); + + _style = style; + } +} + +/** + * Speed optimization for drawing buttons. Draw all unpressed buttons in the + * background layer and draw only the pressed button in the foreground layer. + */ +void BaseNumericAdjustmentScreen::widgets_t::_button(CommandProcessor &cmd, uint8_t tag, int16_t x, int16_t y, int16_t w, int16_t h, progmem_str text, bool enabled, bool highlight) { + if (_what & BACKGROUND) enabled = true; + if ((_what & BACKGROUND) || buttonIsPressed(tag) || highlight || !enabled) { + _button_style(cmd, (!enabled) ? BTN_DISABLED : (highlight ? BTN_ACTION : BTN_NORMAL)); + cmd.tag(enabled ? tag : 0).button(x, y, w, h, text); + } +} + +BaseNumericAdjustmentScreen::widgets_t &BaseNumericAdjustmentScreen::widgets_t::precision(uint8_t decimals, precision_default_t initial) { + _decimals = decimals; + if (screen_data.BaseNumericAdjustment.increment == 0) { + screen_data.BaseNumericAdjustment.increment = 243 + (initial - DEFAULT_LOWEST) - _decimals; + } + return *this; +} + +void BaseNumericAdjustmentScreen::widgets_t::heading(progmem_str label) { + if (_what & BACKGROUND) { + CommandProcessor cmd; + _button_style(cmd, TEXT_LABEL); + cmd.font(font_medium) + .tag(0) + .text( + #if ENABLED(TOUCH_UI_PORTRAIT) + BTN_POS(1, _line), BTN_SIZE(12,1), + #else + BTN_POS(5, _line), BTN_SIZE(8,1), + #endif + label + ); + } + + _line++; +} + +#if ENABLED(TOUCH_UI_PORTRAIT) + #ifdef TOUCH_UI_800x480 + #undef EDGE_R + #define EDGE_R 20 + #else + #undef EDGE_R + #define EDGE_R 10 + #endif +#endif + +void BaseNumericAdjustmentScreen::widgets_t::_draw_increment_btn(CommandProcessor &cmd, uint8_t, const uint8_t tag) { + const char *label = PSTR("?"); + uint8_t pos; + uint8_t & increment = screen_data.BaseNumericAdjustment.increment; + + if (increment == 0) { + increment = tag; // Set the default value to be the first. + } + + switch (tag) { + case 240: label = PSTR( ".001"); pos = _decimals - 3; break; + case 241: label = PSTR( ".01" ); pos = _decimals - 2; break; + case 242: label = PSTR( "0.1" ); pos = _decimals - 1; break; + case 243: label = PSTR( "1" ); pos = _decimals + 0; break; + case 244: label = PSTR( "10" ); pos = _decimals + 1; break; + default: label = PSTR("100" ); pos = _decimals + 2; break; + } + + const bool highlight = (_what & FOREGROUND) && (increment == tag); + + switch (pos) { + #if ENABLED(TOUCH_UI_PORTRAIT) + case 0: _button(cmd, tag, BTN_POS(5,_line), BTN_SIZE(2,1), progmem_str(label), true, highlight); break; + case 1: _button(cmd, tag, BTN_POS(7,_line), BTN_SIZE(2,1), progmem_str(label), true, highlight); break; + case 2: _button(cmd, tag, BTN_POS(9,_line), BTN_SIZE(2,1), progmem_str(label), true, highlight); break; + #else + case 0: _button(cmd, tag, BTN_POS(15,2), BTN_SIZE(4,1), progmem_str(label), true, highlight); break; + case 1: _button(cmd, tag, BTN_POS(15,3), BTN_SIZE(4,1), progmem_str(label), true, highlight); break; + case 2: _button(cmd, tag, BTN_POS(15,4), BTN_SIZE(4,1), progmem_str(label), true, highlight); break; + #endif + } +} + +void BaseNumericAdjustmentScreen::widgets_t::increments() { + CommandProcessor cmd; + + cmd.font(LAYOUT_FONT); + + if (_what & BACKGROUND) { + _button_style(cmd, TEXT_LABEL); + cmd.tag(0).text( + #if ENABLED(TOUCH_UI_PORTRAIT) + BTN_POS(1, _line), BTN_SIZE(4,1), + #else + BTN_POS(15, 1), BTN_SIZE(4,1), + #endif + GET_TEXT_F(MSG_INCREMENT) + ); + } + + _draw_increment_btn(cmd, _line+1, 245 - _decimals); + _draw_increment_btn(cmd, _line+1, 244 - _decimals); + _draw_increment_btn(cmd, _line+1, 243 - _decimals); + + #if ENABLED(TOUCH_UI_PORTRAIT) + _line++; + #endif +} + +void BaseNumericAdjustmentScreen::widgets_t::adjuster_sram_val(uint8_t tag, progmem_str label, const char *value, bool is_enabled) { + CommandProcessor cmd; + + if (_what & BACKGROUND) { + _button_style(cmd, TEXT_LABEL); + cmd.tag(0) + .font(font_small) + .text( BTN_POS(1,_line), BTN_SIZE(4,1), label); + _button_style(cmd, TEXT_AREA); + cmd.fgcolor(_color).button(BTN_POS(5,_line), BTN_SIZE(5,1), F(""), OPT_FLAT); + } + + cmd.font(font_medium); + _button(cmd, tag, BTN_POS(10,_line), BTN_SIZE(2,1), F("-"), is_enabled); + _button(cmd, tag + 1, BTN_POS(12,_line), BTN_SIZE(2,1), F("+"), is_enabled); + + if ((_what & FOREGROUND) && is_enabled) { + _button_style(cmd, BTN_NORMAL); + cmd.tag(0) + .font(font_small) + .text(BTN_POS(5,_line), BTN_SIZE(5,1), value); + } + + _line++; +} + +void BaseNumericAdjustmentScreen::widgets_t::adjuster(uint8_t tag, progmem_str label, const char *value, bool is_enabled) { + if (_what & BACKGROUND) { + adjuster_sram_val(tag, label, nullptr); + } + + if (_what & FOREGROUND) { + char b[strlen_P(value)+1]; + strcpy_P(b,value); + adjuster_sram_val(tag, label, b, is_enabled); + } +} + +void BaseNumericAdjustmentScreen::widgets_t::adjuster(uint8_t tag, progmem_str label, float value, bool is_enabled) { + if (_what & BACKGROUND) { + adjuster_sram_val(tag, label, nullptr); + } + + if (_what & FOREGROUND) { + char b[32]; + dtostrf(value, 5, _decimals, b); + strcat_P(b, PSTR(" ")); + strcat_P(b, (const char*) _units); + adjuster_sram_val(tag, label, b, is_enabled); + } +} + +void BaseNumericAdjustmentScreen::widgets_t::button(uint8_t tag, progmem_str label, bool is_enabled) { + CommandProcessor cmd; + cmd.font(LAYOUT_FONT); + _button(cmd, tag, BTN_POS(5,_line), BTN_SIZE(9,1), label, is_enabled); + + _line++; +} + +void BaseNumericAdjustmentScreen::widgets_t::text_field(uint8_t tag, progmem_str label, const char *value, bool is_enabled) { + CommandProcessor cmd; + + if (_what & BACKGROUND) { + _button_style(cmd, TEXT_LABEL); + cmd.enabled(1) + .tag(0) + .font(font_small) + .text( BTN_POS(1,_line), BTN_SIZE(4,1), label); + _button_style(cmd, TEXT_AREA); + cmd.fgcolor(_color) + .tag(tag) + .button(BTN_POS(5,_line), BTN_SIZE(9,1), F(""), OPT_FLAT); + } + + if (_what & FOREGROUND) { + cmd.font(font_small).text( BTN_POS(5,_line), BTN_SIZE(9,1), is_enabled ? value : "-"); + } + + _line++; +} + +void BaseNumericAdjustmentScreen::widgets_t::two_buttons(uint8_t tag1, progmem_str label1, uint8_t tag2, progmem_str label2, bool is_enabled) { + CommandProcessor cmd; + cmd.font(LAYOUT_FONT); + _button(cmd, tag1, BTN_POS(5,_line), BTN_SIZE(4.5,1), label1, is_enabled); + _button(cmd, tag2, BTN_POS(9.5,_line), BTN_SIZE(4.5,1), label2, is_enabled); + + _line++; +} + +void BaseNumericAdjustmentScreen::widgets_t::toggle(uint8_t tag, progmem_str label, bool value, bool is_enabled) { + CommandProcessor cmd; + + if (_what & BACKGROUND) { + _button_style(cmd, TEXT_LABEL); + cmd.font(font_small) + .text( + #if ENABLED(TOUCH_UI_PORTRAIT) + BTN_POS(1, _line), BTN_SIZE( 8,1), + #else + BTN_POS(1, _line), BTN_SIZE(10,1), + #endif + label + ); + } + + if (_what & FOREGROUND) { + _button_style(cmd, BTN_TOGGLE); + cmd.tag(is_enabled ? tag : 0) + .enabled(is_enabled) + .font(font_small) + .toggle2( + #if ENABLED(TOUCH_UI_PORTRAIT) + BTN_POS( 9,_line), BTN_SIZE(5,1), + #else + BTN_POS(10,_line), BTN_SIZE(4,1), + #endif + GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), value + ); + } + + _line++; +} + +void BaseNumericAdjustmentScreen::widgets_t::home_buttons(uint8_t tag) { + CommandProcessor cmd; + + if (_what & BACKGROUND) { + _button_style(cmd, TEXT_LABEL); + cmd.font(font_small) + .text(BTN_POS(1, _line), BTN_SIZE(4,1), GET_TEXT_F(MSG_HOME)); + } + + cmd.font(LAYOUT_FONT); + _button(cmd, tag+0, BTN_POS(5,_line), BTN_SIZE(2,1), GET_TEXT_F(MSG_AXIS_X)); + _button(cmd, tag+1, BTN_POS(7,_line), BTN_SIZE(2,1), GET_TEXT_F(MSG_AXIS_Y)); + #if DISABLED(Z_SAFE_HOMING) + _button(cmd, tag+2, BTN_POS(9,_line), BTN_SIZE(2,1), GET_TEXT_F(MSG_AXIS_Z)); + _button(cmd, tag+3, BTN_POS(11,_line), BTN_SIZE(3,1), GET_TEXT_F(MSG_AXIS_ALL)); + #else + _button(cmd, tag+3, BTN_POS(9,_line), BTN_SIZE(3,1), GET_TEXT_F(MSG_AXIS_ALL)); + #endif + + _line++; +} + +void BaseNumericAdjustmentScreen::onEntry() { + screen_data.BaseNumericAdjustment.increment = 0; // This will force the increment to be picked while drawing. + BaseScreen::onEntry(); + CommandProcessor cmd; + cmd.set_button_style_callback(nullptr); +} + +bool BaseNumericAdjustmentScreen::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); return true; + case 240 ... 245: screen_data.BaseNumericAdjustment.increment = tag; break; + default: return current_screen.onTouchHeld(tag); + } + return true; +} + +float BaseNumericAdjustmentScreen::getIncrement() { + switch (screen_data.BaseNumericAdjustment.increment) { + case 240: return 0.001; + case 241: return 0.01; + case 242: return 0.1; + case 243: return 1.0; + case 244: return 10.0; + case 245: return 100.0; + default: return 0.0; + } +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_screen.cpp new file mode 100644 index 0000000..16b26e6 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/base_screen.cpp @@ -0,0 +1,90 @@ +/******************* + * base_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +void BaseScreen::onEntry() { + CommandProcessor cmd; + cmd.set_button_style_callback(buttonStyleCallback); + reset_menu_timeout(); + UIScreen::onEntry(); +} + +bool BaseScreen::buttonIsPressed(uint8_t tag) { + return tag != 0 && EventLoop::get_pressed_tag() == tag; +} + +bool BaseScreen::buttonStyleCallback(CommandProcessor &cmd, uint8_t tag, uint8_t &style, uint16_t &options, bool post) { + if (post) { + cmd.colors(normal_btn); + return false; + } + + #if LCD_TIMEOUT_TO_STATUS > 0 + if (EventLoop::get_pressed_tag() != 0) { + reset_menu_timeout(); + } + #endif + + if (buttonIsPressed(tag)) { + options = OPT_FLAT; + } + + if (style & cmd.STYLE_DISABLED) { + cmd.tag(0); + style &= ~cmd.STYLE_DISABLED; + cmd.colors(disabled_btn); + return true; // Call me again to reset the colors + } + return false; +} + +void BaseScreen::onIdle() { + #if LCD_TIMEOUT_TO_STATUS > 0 + if ((millis() - last_interaction) > LCD_TIMEOUT_TO_STATUS) { + reset_menu_timeout(); + #if ENABLED(TOUCH_UI_DEBUG) + SERIAL_ECHO_MSG("Returning to status due to menu timeout"); + #endif + GOTO_SCREEN(StatusScreen); + } + #endif +} + +void BaseScreen::reset_menu_timeout() { + #if LCD_TIMEOUT_TO_STATUS > 0 + last_interaction = millis(); + #endif +} + +#if LCD_TIMEOUT_TO_STATUS > 0 + uint32_t BaseScreen::last_interaction; +#endif + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bed_mesh_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bed_mesh_screen.cpp new file mode 100644 index 0000000..9fb2b20 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bed_mesh_screen.cpp @@ -0,0 +1,341 @@ +/*********************** + * bed_mesh_screen.cpp * + ***********************/ + +/**************************************************************************** + * Written By Marcio Teixeira 2020 * + * * + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, HAS_MESH) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace Theme; +using namespace ExtUI; + +#if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_COLS 2 + #define GRID_ROWS 10 + + #define MESH_POS BTN_POS(1, 2), BTN_SIZE(2,5) + #define MESSAGE_POS BTN_POS(1, 7), BTN_SIZE(2,1) + #define Z_LABEL_POS BTN_POS(1, 8), BTN_SIZE(1,1) + #define Z_VALUE_POS BTN_POS(2, 8), BTN_SIZE(1,1) + #define OKAY_POS BTN_POS(1,10), BTN_SIZE(2,1) +#else + #define GRID_COLS 5 + #define GRID_ROWS 5 + + #define MESH_POS BTN_POS(1,1), BTN_SIZE(3,5) + #define MESSAGE_POS BTN_POS(4,1), BTN_SIZE(2,1) + #define Z_LABEL_POS BTN_POS(4,2), BTN_SIZE(2,1) + #define Z_VALUE_POS BTN_POS(4,3), BTN_SIZE(2,1) + #define OKAY_POS BTN_POS(4,5), BTN_SIZE(2,1) +#endif + +void BedMeshScreen::drawMesh(int16_t x, int16_t y, int16_t w, int16_t h, ExtUI::bed_mesh_t data, uint8_t opts, float autoscale_max) { + constexpr uint8_t rows = GRID_MAX_POINTS_Y; + constexpr uint8_t cols = GRID_MAX_POINTS_X; + + #define VALUE(X,Y) (data ? data[X][Y] : 0) + #define ISVAL(X,Y) (data ? !isnan(VALUE(X,Y)) : true) + #define HEIGHT(X,Y) (ISVAL(X,Y) ? (VALUE(X,Y) - val_min) * scale_z : 0) + + // Compute the mean, min and max for the points + + float val_mean = 0; + float val_max = -INFINITY; + float val_min = INFINITY; + uint8_t val_cnt = 0; + + if (data && (opts & USE_AUTOSCALE)) { + for (uint8_t y = 0; y < rows; y++) { + for (uint8_t x = 0; x < cols; x++) { + if (ISVAL(x,y)) { + const float val = VALUE(x,y); + val_mean += val; + val_max = max(val_max, val); + val_min = min(val_min, val); + val_cnt++; + } + } + } + } + if (val_cnt) + val_mean /= val_cnt; + else { + val_mean = 0; + val_min = 0; + val_max = 0; + } + + const float scale_z = ((val_max == val_min) ? 1 : 1/(val_max - val_min)) * autoscale_max; + + /** + * The 3D points go through a 3D graphics pipeline to determine the final 2D point on the screen. + * This is written out as a stack of macros that each apply an affine transformation to the point. + * At compile time, the compiler should be able to reduce these expressions. + * + * The last transformation in the chain (TRANSFORM_5) is initially set to a no-op so we can measure + * the dimensions of the grid, but is later replaced with a scaling transform that scales the grid + * to fit. + */ + + #define TRANSFORM_5(X,Y,Z) (X), (Y) // No transform + #define TRANSFORM_4(X,Y,Z) TRANSFORM_5((X)/(Z),(Y)/-(Z), 0) // Perspective + #define TRANSFORM_3(X,Y,Z) TRANSFORM_4((X), (Z), (Y)) // Swap Z and Y + #define TRANSFORM_2(X,Y,Z) TRANSFORM_3((X), (Y) + 2.5, (Z) - 1) // Translate + #define TRANSFORM(X,Y,Z) TRANSFORM_2(float(X)/(cols-1) - 0.5, float(Y)/(rows-1) - 0.5, (Z)) // Normalize + + // Compute the bounding box for the grid prior to scaling. Do this at compile-time by + // transforming the four corner points via the transformation equations and finding + // the min and max for each axis. + + constexpr float bounds[][3] = {{TRANSFORM(0 , 0 , 0)}, + {TRANSFORM(cols-1, 0 , 0)}, + {TRANSFORM(0 , rows-1, 0)}, + {TRANSFORM(cols-1, rows-1, 0)}}; + #define APPLY(FUNC, AXIS) FUNC(FUNC(bounds[0][AXIS], bounds[1][AXIS]), FUNC(bounds[2][AXIS], bounds[3][AXIS])) + constexpr float grid_x = APPLY(min,0); + constexpr float grid_y = APPLY(min,1); + constexpr float grid_w = APPLY(max,0) - grid_x; + constexpr float grid_h = APPLY(max,1) - grid_y; + constexpr float grid_cx = grid_x + grid_w/2; + constexpr float grid_cy = grid_y + grid_h/2; + + // Figure out scale and offset such that the grid fits within the rectangle given by (x,y,w,h) + + const float scale_x = float(w)/grid_w; + const float scale_y = float(h)/grid_h; + const float center_x = x + w/2; + const float center_y = y + h/2; + + // Now replace the last transformation in the chain with a scaling operation. + + #undef TRANSFORM_5 + #define TRANSFORM_6(X,Y,Z) (X)*16, (Y)*16 // Scale to 1/16 pixel units + #define TRANSFORM_5(X,Y,Z) TRANSFORM_6( center_x + ((X) - grid_cx) * scale_x, \ + center_y + ((Y) - grid_cy) * scale_y, 0) // Scale to bounds + + // Draw the grid + + const uint16_t basePointSize = min(w,h) / max(cols,rows); + + CommandProcessor cmd; + cmd.cmd(SAVE_CONTEXT()) + .cmd(TAG_MASK(false)) + .cmd(SAVE_CONTEXT()); + + for (uint8_t y = 0; y < rows; y++) { + for (uint8_t x = 0; x < cols; x++) { + if (ISVAL(x,y)) { + const bool hasLeftSegment = x < cols - 1 && ISVAL(x+1,y); + const bool hasRightSegment = y < rows - 1 && ISVAL(x,y+1); + if (hasLeftSegment || hasRightSegment) { + cmd.cmd(BEGIN(LINE_STRIP)); + if (hasLeftSegment) cmd.cmd(VERTEX2F(TRANSFORM(x + 1, y , HEIGHT(x + 1, y )))); + cmd.cmd( VERTEX2F(TRANSFORM(x , y , HEIGHT(x , y )))); + if (hasRightSegment) cmd.cmd(VERTEX2F(TRANSFORM(x , y + 1, HEIGHT(x , y + 1)))); + } + } + } + + if (opts & USE_POINTS) { + const float sq_min = sq(val_min - val_mean); + const float sq_max = sq(val_max - val_mean); + cmd.cmd(POINT_SIZE(basePointSize * 2)); + cmd.cmd(BEGIN(POINTS)); + for (uint8_t x = 0; x < cols; x++) { + if (ISVAL(x,y)) { + if (opts & USE_COLORS) { + const float val_dev = VALUE(x, y) - val_mean; + const uint8_t neg_byte = sq(val_dev) / (val_dev < 0 ? sq_min : sq_max) * 0xFF; + const uint8_t pos_byte = 255 - neg_byte; + cmd.cmd(COLOR_RGB(pos_byte, pos_byte, 0xFF)); + } + cmd.cmd(VERTEX2F(TRANSFORM(x, y, HEIGHT(x, y)))); + } + } + if (opts & USE_COLORS) { + cmd.cmd(RESTORE_CONTEXT()) + .cmd(SAVE_CONTEXT()); + } + } + } + cmd.cmd(RESTORE_CONTEXT()) + .cmd(TAG_MASK(true)); + + if (opts & USE_TAGS) { + cmd.cmd(COLOR_MASK(false, false, false, false)) + .cmd(POINT_SIZE(basePointSize * 10)) + .cmd(BEGIN(POINTS)); + for (uint8_t y = 0; y < rows; y++) { + for (uint8_t x = 0; x < cols; x++) { + const uint8_t tag = pointToTag(x, y); + cmd.tag(tag).cmd(VERTEX2F(TRANSFORM(x, y, HEIGHT(x, y)))); + } + } + cmd.cmd(COLOR_MASK(true, true, true, true)); + } + + if (opts & USE_HIGHLIGHT) { + const uint8_t tag = screen_data.BedMesh.highlightedTag; + uint8_t x, y; + if (tagToPoint(tag, x, y)) { + cmd.cmd(COLOR_A(128)) + .cmd(POINT_SIZE(basePointSize * 6)) + .cmd(BEGIN(POINTS)) + .tag(tag).cmd(VERTEX2F(TRANSFORM(x, y, HEIGHT(x, y)))); + } + } + cmd.cmd(END()); + cmd.cmd(RESTORE_CONTEXT()); +} + +uint8_t BedMeshScreen::pointToTag(uint8_t x, uint8_t y) { + return y * (GRID_MAX_POINTS_X) + x + 10; +} + +bool BedMeshScreen::tagToPoint(uint8_t tag, uint8_t &x, uint8_t &y) { + if (tag < 10) return false; + x = (tag - 10) % (GRID_MAX_POINTS_X); + y = (tag - 10) / (GRID_MAX_POINTS_X); + return true; +} + +void BedMeshScreen::onEntry() { + screen_data.BedMesh.highlightedTag = 0; + screen_data.BedMesh.count = GRID_MAX_POINTS; + screen_data.BedMesh.message = screen_data.BedMesh.MSG_NONE; + BaseScreen::onEntry(); +} + +float BedMeshScreen::getHightlightedValue() { + if (screen_data.BedMesh.highlightedTag) { + xy_uint8_t pt; + tagToPoint(screen_data.BedMesh.highlightedTag, pt.x, pt.y); + return ExtUI::getMeshPoint(pt); + } + return NAN; +} + +void BedMeshScreen::drawHighlightedPointValue() { + char str[16]; + const float val = getHightlightedValue(); + const bool isGood = !isnan(val); + if (isGood) + dtostrf(val, 5, 3, str); + else + strcpy_P(str, PSTR("-")); + + CommandProcessor cmd; + cmd.font(Theme::font_medium) + .text(Z_LABEL_POS, GET_TEXT_F(MSG_MESH_EDIT_Z)) + .text(Z_VALUE_POS, str) + .colors(action_btn) + .tag(1).button(OKAY_POS, GET_TEXT_F(MSG_BUTTON_OKAY)) + .tag(0); + + switch (screen_data.BedMesh.message) { + case screen_data.BedMesh.MSG_MESH_COMPLETE: cmd.text(MESSAGE_POS, GET_TEXT_F(MSG_BED_MAPPING_DONE)); break; + case screen_data.BedMesh.MSG_MESH_INCOMPLETE: cmd.text(MESSAGE_POS, GET_TEXT_F(MSG_BED_MAPPING_INCOMPLETE)); break; + default: break; + } +} + +void BedMeshScreen::onRedraw(draw_mode_t what) { + #define _INSET_POS(x,y,w,h) x + min(w,h)/10, y + min(w,h)/10, w - min(w,h)/5, h - min(w,h)/5 + #define INSET_POS(pos) _INSET_POS(pos) + + if (what & BACKGROUND) { + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)); + + // Draw the shadow and tags + cmd.cmd(COLOR_RGB(0x444444)); + BedMeshScreen::drawMesh(INSET_POS(MESH_POS), nullptr, USE_POINTS | USE_TAGS); + cmd.cmd(COLOR_RGB(bg_text_enabled)); + } + + if (what & FOREGROUND) { + constexpr float autoscale_max_amplitude = 0.03; + const bool gotAllPoints = screen_data.BedMesh.count >= GRID_MAX_POINTS; + if (gotAllPoints) { + drawHighlightedPointValue(); + } + const float levelingProgress = sq(float(screen_data.BedMesh.count) / GRID_MAX_POINTS); + BedMeshScreen::drawMesh(INSET_POS(MESH_POS), ExtUI::getMeshArray(), + USE_POINTS | USE_HIGHLIGHT | USE_AUTOSCALE | (gotAllPoints ? USE_COLORS : 0), + autoscale_max_amplitude * levelingProgress + ); + } +} + +bool BedMeshScreen::onTouchStart(uint8_t tag) { + screen_data.BedMesh.highlightedTag = tag; + return true; +} + +bool BedMeshScreen::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: + GOTO_PREVIOUS(); + return true; + default: + return false; + } +} + +void BedMeshScreen::onMeshUpdate(const int8_t, const int8_t, const float) { + if (AT_SCREEN(BedMeshScreen)) + onRefresh(); +} + +void BedMeshScreen::onMeshUpdate(const int8_t x, const int8_t y, const ExtUI::probe_state_t state) { + switch (state) { + case ExtUI::MESH_START: + screen_data.BedMesh.count = 0; + screen_data.BedMesh.message = screen_data.BedMesh.MSG_NONE; + break; + case ExtUI::MESH_FINISH: + if (screen_data.BedMesh.count == GRID_MAX_POINTS && ExtUI::getMeshValid()) + screen_data.BedMesh.message = screen_data.BedMesh.MSG_MESH_COMPLETE; + else + screen_data.BedMesh.message = screen_data.BedMesh.MSG_MESH_INCOMPLETE; + screen_data.BedMesh.count = GRID_MAX_POINTS; + break; + case ExtUI::PROBE_START: + screen_data.BedMesh.highlightedTag = pointToTag(x, y); + break; + case ExtUI::PROBE_FINISH: + screen_data.BedMesh.count++; + break; + } + BedMeshScreen::onMeshUpdate(x, y, 0); +} + +void BedMeshScreen::startMeshProbe() { + GOTO_SCREEN(BedMeshScreen); + screen_data.BedMesh.count = 0; + injectCommands_P(PSTR(BED_LEVELING_COMMANDS)); +} + +#endif // TOUCH_UI_FTDI_EVE && HAS_MESH diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_advanced_settings.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_advanced_settings.cpp new file mode 100644 index 0000000..cabcd5d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_advanced_settings.cpp @@ -0,0 +1,137 @@ +/***************************** + * bio_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +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) + #define GRID_ROWS 9 + #define GRID_COLS 2 + + .tag(2) .button(BTN_POS(1,1), BTN_SIZE(1,1), GET_TEXT_F(MSG_DISPLAY_MENU)) + .enabled( + #if HAS_TRINAMIC_CONFIG + 1 + #endif + ) + .tag(3) .button(BTN_POS(1,2), BTN_SIZE(1,1), GET_TEXT_F(MSG_TMC_CURRENT)) + .enabled( + #if HAS_TRINAMIC_CONFIG + 1 + #endif + ) + .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( + #if HAS_MULTI_HOTEND + 1 + #endif + ) + .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_VELOCITY)) + .tag(9) .button(BTN_POS(2,3), BTN_SIZE(1,1), GET_TEXT_F(MSG_ACCELERATION)) + #if HAS_JUNCTION_DEVIATION + .tag(10) .button(BTN_POS(2,4), BTN_SIZE(1,1), GET_TEXT_F(MSG_JUNCTION_DEVIATION)) + #else + .tag(10) .button(BTN_POS(2,4), BTN_SIZE(1,1), GET_TEXT_F(MSG_JERK)) + #endif + .enabled( + #if ENABLED(BACKLASH_GCODE) + 1 + #endif + ) + .tag(11) .button(BTN_POS(2,5), BTN_SIZE(1,1), GET_TEXT_F(MSG_BACKLASH)) + .enabled( + #if ENABLED(LIN_ADVANCE) + 1 + #endif + ) + .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_BACK)); + #undef GRID_COLS + #undef GRID_ROWS + } +} + +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: + #if HAS_JUNCTION_DEVIATION + GOTO_SCREEN(JunctionDeviationScreen); + #else + GOTO_SCREEN(JerkScreen); + #endif + 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 // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_e.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_e.cpp new file mode 100644 index 0000000..3f6b411 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_e.cpp @@ -0,0 +1,57 @@ +/**************************** + * bio_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO) + +#include "screens.h" + +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_P(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 // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_xyz.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_xyz.cpp new file mode 100644 index 0000000..f712fdf --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_confirm_home_xyz.cpp @@ -0,0 +1,56 @@ +/**************************** + * bio_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO) + +#include "screens.h" + +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_P(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 // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_main_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_main_menu.cpp new file mode 100644 index 0000000..53203cd --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_main_menu.cpp @@ -0,0 +1,88 @@ +/********************* + * bio_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +void MainMenu::onRedraw(draw_mode_t what) { + #define GRID_ROWS 10 + #define GRID_COLS 2 + + 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_BACK)); + } + + #undef GRID_COLS + #undef GRID_ROWS +} + +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_P(e_homed ? F("G0 E0 F120") : F("G112")); break; + case 4: StatusScreen::unlockMotors(); break; + #ifdef AXIS_LEVELING_COMMANDS + case 5: SpinnerDialogBox::enqueueAndWait_P(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 // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_landscape.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_landscape.h new file mode 100644 index 0000000..4faddc6 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_landscape.h @@ -0,0 +1,59 @@ + +/**************************************************************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/** + * 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_portrait.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_portrait.h new file mode 100644 index 0000000..50fc5ab --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printer_ui_portrait.h @@ -0,0 +1,52 @@ + +/**************************************************************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/** + * 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/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printing_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printing_dialog_box.cpp new file mode 100644 index 0000000..65b996d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_printing_dialog_box.cpp @@ -0,0 +1,151 @@ +/******************************* + * bio_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO) + +#include "screens.h" + +#include "../ftdi_eve_lib/extras/circular_progress.h" + +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* message) { + 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), message, 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(progmem_str message) { + char buff[strlen_P((const char*)message)+1]; + strcpy_P(buff, (const char*) message); + setStatusMessage(buff); +} + +void BioPrintingDialogBox::setStatusMessage(const char* message) { + CommandProcessor cmd; + cmd.cmd(CMD_DLSTART) + .cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)); + + draw_status_message(BACKGROUND, message); + draw_progress(BACKGROUND); + draw_time_remaining(BACKGROUND); + draw_interaction_buttons(BACKGROUND); + storeBackground(); + + #if ENABLED(TOUCH_UI_DEBUG) + SERIAL_ECHO_START(); + SERIAL_ECHOLNPAIR("New status message: ", message); + #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 // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_status_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_status_screen.cpp new file mode 100644 index 0000000..90d8d62 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_status_screen.cpp @@ -0,0 +1,379 @@ +/************************* + * bio_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO) + +#include "screens.h" + +#include "../ftdi_eve_lib/extras/poly_ui.h" + +#if ENABLED(TOUCH_UI_PORTRAIT) + #include "bio_printer_ui_portrait.h" +#else + #include "bio_printer_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_P(PSTR("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_P(PSTR("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_P(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(progmem_str pstr) { + BioPrintingDialogBox::setStatusMessage(pstr); +} + +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 // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_tune_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_tune_menu.cpp new file mode 100644 index 0000000..dacc1cb --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/bio_tune_menu.cpp @@ -0,0 +1,79 @@ +/********************* + * bio_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_LULZBOT_BIO) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; +using namespace ExtUI; + +void TuneMenu::onRedraw(draw_mode_t what) { + #define GRID_ROWS 8 + #define GRID_COLS 2 + + 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_BACK)); + } + #undef GRID_COLS + #undef GRID_ROWS +} + +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_P(F("G0 E0 F120")); break; + case 7: StatusScreen::unlockMotors(); break; + default: + return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE && TOUCH_UI_LULZBOT_BIO diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/boot_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/boot_screen.cpp new file mode 100644 index 0000000..a6a8705 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/boot_screen.cpp @@ -0,0 +1,130 @@ +/******************* + * boot_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +#include "../ftdi_eve_lib/extras/poly_ui.h" +#include "../archim2-flash/flash_storage.h" + +#if ENABLED(SHOW_CUSTOM_BOOTSCREEN) + #if ENABLED(TOUCH_UI_PORTRAIT) + #include "../theme/bootscreen_logo_portrait.h" + #else + #include "../theme/_bootscreen_landscape.h" + #endif +#else + #if ENABLED(TOUCH_UI_PORTRAIT) + #include "../theme/marlin_bootscreen_portrait.h" + #else + #include "../theme/marlin_bootscreen_landscape.h" + #endif +#endif + +using namespace FTDI; +using namespace Theme; + +void BootScreen::onRedraw(draw_mode_t) { + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(0x000000)); + cmd.cmd(CLEAR(true,true,true)); + + CLCD::turn_on_backlight(); + SoundPlayer::set_volume(255); +} + +void BootScreen::onIdle() { + if (CLCD::is_touching()) { + // If the user is touching the screen at startup, then + // assume the user wants to re-calibrate the screen. + // This gives the user the ability to recover a + // miscalibration that has been stored to EEPROM. + + // Also reset display parameters to defaults, just + // in case the display is borked. + InterfaceSettingsScreen::failSafeSettings(); + + StatusScreen::loadBitmaps(); + StatusScreen::setStatusMessage(GET_TEXT_F(WELCOME_MSG)); + GOTO_SCREEN(TouchCalibrationScreen); + current_screen.forget(); + PUSH_SCREEN(StatusScreen); + } + else { + if (!UIFlashStorage::is_valid()) { + StatusScreen::loadBitmaps(); + SpinnerDialogBox::show(GET_TEXT_F(MSG_PLEASE_WAIT)); + UIFlashStorage::format_flash(); + SpinnerDialogBox::hide(); + } + + #if DISABLED(TOUCH_UI_NO_BOOTSCREEN) + if (UIData::animations_enabled()) { + // If there is a startup video in the flash SPI, play + // that, otherwise show a static splash screen. + if (!MediaPlayerScreen::playBootMedia()) + showSplashScreen(); + } + #endif + + StatusScreen::loadBitmaps(); + + #if ENABLED(TOUCH_UI_LULZBOT_BIO) + GOTO_SCREEN(BioConfirmHomeXYZ); + current_screen.forget(); + PUSH_SCREEN(StatusScreen); + PUSH_SCREEN(BioConfirmHomeE); + #elif NUM_LANGUAGES > 1 + StatusScreen::setStatusMessage(GET_TEXT_F(WELCOME_MSG)); + GOTO_SCREEN(LanguageMenu); + #else + StatusScreen::setStatusMessage(GET_TEXT_F(WELCOME_MSG)); + GOTO_SCREEN(StatusScreen); + #endif + } +} + +void BootScreen::showSplashScreen() { + CommandProcessor cmd; + cmd.cmd(CMD_DLSTART); + cmd.cmd(CLEAR_COLOR_RGB(LOGO_BACKGROUND)); + cmd.cmd(CLEAR(true,true,true)); + + #define POLY(A) PolyUI::poly_reader_t(A, sizeof(A)/sizeof(A[0])) + #define LOGO_PAINT_PATH(rgb, path) cmd.cmd(COLOR_RGB(rgb)); ui.fill(POLY(path)); + + PolyUI ui(cmd); + + LOGO_PAINT_PATHS + + cmd.cmd(DL::DL_DISPLAY); + cmd.cmd(CMD_SWAP); + cmd.execute(); + + ExtUI::delay_ms(2500); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/case_light_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/case_light_screen.cpp new file mode 100644 index 0000000..5b2b7d4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/case_light_screen.cpp @@ -0,0 +1,62 @@ +/************************* + * case_light_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, CASE_LIGHT_ENABLE) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void CaseLightScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.heading( GET_TEXT_F(MSG_CASE_LIGHT)); + w.toggle( 2, GET_TEXT_F(MSG_LEDS), getCaseLightState()); + #if DISABLED(CASE_LIGHT_NO_BRIGHTNESS) + w.precision(0).units(GET_TEXT_F(MSG_UNITS_PERCENT)) + .adjuster(10, GET_TEXT_F(MSG_CASE_LIGHT_BRIGHTNESS), getCaseLightBrightness_percent()); + w.precision(0).increments(); + #endif +} + +bool CaseLightScreen::onTouchHeld(uint8_t tag) { + using namespace ExtUI; + #if DISABLED(CASE_LIGHT_NO_BRIGHTNESS) + const float increment = getIncrement(); + #endif + switch (tag) { + case 2: setCaseLightState(!getCaseLightState()); break; + #if DISABLED(CASE_LIGHT_NO_BRIGHTNESS) + case 10: UI_DECREMENT(CaseLightBrightness_percent); break; + case 11: UI_INCREMENT(CaseLightBrightness_percent); break; + #endif + default: + return false; + } + + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/change_filament_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/change_filament_screen.cpp new file mode 100644 index 0000000..624bb26 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/change_filament_screen.cpp @@ -0,0 +1,330 @@ +/****************************** + * change_filament_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +using namespace ExtUI; +using namespace FTDI; +using namespace Theme; + +#ifdef TOUCH_UI_PORTRAIT + #define GRID_COLS 2 + #define GRID_ROWS 11 + #define E_TEMP_POS BTN_POS(2,7), BTN_SIZE(1,1) + #define E_TEMP_LBL_POS BTN_POS(1,7), BTN_SIZE(1,1) + #define UNLD_LABL_POS BTN_POS(1,8), BTN_SIZE(1,1) + #define LOAD_LABL_POS BTN_POS(2,8), BTN_SIZE(1,1) + #define UNLD_MOMN_POS BTN_POS(1,9), BTN_SIZE(1,1) + #define LOAD_MOMN_POS BTN_POS(2,9), BTN_SIZE(1,1) + #define UNLD_CONT_POS BTN_POS(1,10), BTN_SIZE(1,1) + #define LOAD_CONT_POS BTN_POS(2,10), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(1,11), BTN_SIZE(2,1) +#else + #define GRID_COLS 4 + #define GRID_ROWS 6 + #define E_TEMP_POS BTN_POS(3,2), BTN_SIZE(2,1) + #define E_TEMP_LBL_POS BTN_POS(3,1), BTN_SIZE(2,1) + #define UNLD_LABL_POS BTN_POS(3,3), BTN_SIZE(1,1) + #define LOAD_LABL_POS BTN_POS(4,3), BTN_SIZE(1,1) + #define UNLD_MOMN_POS BTN_POS(3,4), BTN_SIZE(1,1) + #define LOAD_MOMN_POS BTN_POS(4,4), BTN_SIZE(1,1) + #define UNLD_CONT_POS BTN_POS(3,5), BTN_SIZE(1,1) + #define LOAD_CONT_POS BTN_POS(4,5), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(3,6), BTN_SIZE(2,1) +#endif +#define REMOVAL_TEMP_LBL_POS BTN_POS(1,3), BTN_SIZE(2,1) +#define GRADIENT_POS BTN_POS(1,4), BTN_SIZE(1,3) +#define LOW_TEMP_POS BTN_POS(2,6), BTN_SIZE(1,1) +#define MED_TEMP_POS BTN_POS(2,5), BTN_SIZE(1,1) +#define HIG_TEMP_POS BTN_POS(2,4), BTN_SIZE(1,1) +#define HEATING_LBL_POS BTN_POS(1,6), BTN_SIZE(1,1) +#define CAUTION_LBL_POS BTN_POS(1,4), BTN_SIZE(1,1) +#define HOT_LBL_POS BTN_POS(1,6), BTN_SIZE(1,1) +#define E_SEL_LBL_POS BTN_POS(1,1), BTN_SIZE(2,1) +#define E1_SEL_POS BTN_POS(1,2), BTN_SIZE(1,1) +#define E2_SEL_POS BTN_POS(2,2), BTN_SIZE(1,1) + +#define COOL_TEMP 40 +#define LOW_TEMP 180 +#define MED_TEMP 200 +#define HIGH_TEMP 220 + +/****************** COLOR SCALE ***********************/ + +uint32_t getWarmColor(uint16_t temp, uint16_t cool, uint16_t low, uint16_t med, uint16_t high) { + rgb_t R0, R1, mix; + + float t; + if (temp < cool) { + R0 = cool_rgb; + R1 = low_rgb; + t = 0; + } + else if (temp < low) { + R0 = cool_rgb; + R1 = low_rgb; + t = (float(temp)-cool)/(low-cool); + } + else if (temp < med) { + R0 = low_rgb; + R1 = med_rgb; + t = (float(temp)-low)/(med-low); + } + else if (temp < high) { + R0 = med_rgb; + R1 = high_rgb; + t = (float(temp)-med)/(high-med); + } + else if (temp >= high) { + R0 = med_rgb; + R1 = high_rgb; + t = 1; + } + rgb_t::lerp(t, R0, R1, mix); + return mix; +} + +void ChangeFilamentScreen::drawTempGradient(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + CommandProcessor cmd; + cmd.cmd(SCISSOR_XY (x, y)) + .cmd(SCISSOR_SIZE (w, h/2)) + .gradient (x, y, high_rgb, x, y+h/2, med_rgb) + .cmd(SCISSOR_XY (x, y+h/2)) + .cmd(SCISSOR_SIZE (w, h/2)) + .gradient (x, y+h/2, med_rgb, x, y+h, low_rgb) + .cmd(SCISSOR_XY ()) + .cmd(SCISSOR_SIZE ()); +} + +void ChangeFilamentScreen::onEntry() { + BaseScreen::onEntry(); + screen_data.ChangeFilament.e_tag = ExtUI::getActiveTool() + 10; + screen_data.ChangeFilament.t_tag = 0; + screen_data.ChangeFilament.repeat_tag = 0; + screen_data.ChangeFilament.saved_extruder = getActiveTool(); + #if FILAMENT_UNLOAD_PURGE_LENGTH > 0 + screen_data.ChangeFilament.need_purge = true; + #endif +} + +void ChangeFilamentScreen::onExit() { + setActiveTool(screen_data.ChangeFilament.saved_extruder, true); +} + +void ChangeFilamentScreen::onRedraw(draw_mode_t what) { + CommandProcessor cmd; + + if (what & BACKGROUND) { + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0) + .font(TERN(TOUCH_UI_PORTRAIT, font_large, font_medium)) + .text(E_SEL_LBL_POS, GET_TEXT_F(MSG_EXTRUDER_SELECTION)) + .text(E_TEMP_LBL_POS, GET_TEXT_F(MSG_CURRENT_TEMPERATURE)) + .text(REMOVAL_TEMP_LBL_POS, GET_TEXT_F(MSG_REMOVAL_TEMPERATURE)); + drawTempGradient(GRADIENT_POS); + } + + if (what & FOREGROUND) { + char str[15]; + const extruder_t e = getExtruder(); + + if (isHeaterIdle(e)) + format_temp_and_idle(str, getActualTemp_celsius(e)); + else + format_temp_and_temp(str, getActualTemp_celsius(e), getTargetTemp_celsius(e)); + + const rgb_t tcol = getWarmColor(getActualTemp_celsius(e), COOL_TEMP, LOW_TEMP, MED_TEMP, HIGH_TEMP); + cmd.cmd(COLOR_RGB(tcol)) + .tag(15) + .rectangle(E_TEMP_POS) + .cmd(COLOR_RGB(tcol.luminance() > 128 ? 0x000000 : 0xFFFFFF)) + .font(font_medium) + .text(E_TEMP_POS, str) + .colors(normal_btn); + + const bool t_ok = getActualTemp_celsius(e) > getSoftenTemp() - 10; + + if (screen_data.ChangeFilament.t_tag && !t_ok) { + cmd.text(HEATING_LBL_POS, GET_TEXT_F(MSG_HEATING)); + } else if (getActualTemp_celsius(e) > 100) { + cmd.cmd(COLOR_RGB(0xFF0000)) + .text(CAUTION_LBL_POS, GET_TEXT_F(MSG_CAUTION)) + .colors(normal_btn) + .text(HOT_LBL_POS, GET_TEXT_F(MSG_HOT)); + } + + #define TOG_STYLE(A) colors(A ? action_btn : normal_btn) + + const bool tog2 = screen_data.ChangeFilament.t_tag == 2; + const bool tog3 = screen_data.ChangeFilament.t_tag == 3; + const bool tog4 = screen_data.ChangeFilament.t_tag == 4; + const bool tog10 = screen_data.ChangeFilament.e_tag == 10; + #if HAS_MULTI_HOTEND + const bool tog11 = screen_data.ChangeFilament.e_tag == 11; + #endif + + cmd.TOG_STYLE(tog10) + .tag(10).button (E1_SEL_POS, F("1")) + #if HOTENDS < 2 + .enabled(false) + #else + .TOG_STYLE(tog11) + #endif + .tag(11).button (E2_SEL_POS, F("2")); + + if (!t_ok) reset_menu_timeout(); + + const bool tog7 = screen_data.ChangeFilament.repeat_tag == 7; + const bool tog8 = screen_data.ChangeFilament.repeat_tag == 8; + + { + char str[30]; + format_temp(str, LOW_TEMP); + cmd.tag(2) .TOG_STYLE(tog2).button (LOW_TEMP_POS, str); + + format_temp(str, MED_TEMP); + cmd.tag(3) .TOG_STYLE(tog3).button (MED_TEMP_POS, str); + + format_temp(str, HIGH_TEMP); + cmd.tag(4) .TOG_STYLE(tog4).button (HIG_TEMP_POS, str); + } + + cmd.cmd(COLOR_RGB(t_ok ? bg_text_enabled : bg_text_disabled)) + .tag(0) .text (UNLD_LABL_POS, GET_TEXT_F(MSG_UNLOAD_FILAMENT)) + .text (LOAD_LABL_POS, GET_TEXT_F(MSG_LOAD_FILAMENT)) + .colors(normal_btn) + .tag(5) .enabled(t_ok).button (UNLD_MOMN_POS, GET_TEXT_F(MSG_MOMENTARY)) + .tag(6) .enabled(t_ok).button (LOAD_MOMN_POS, GET_TEXT_F(MSG_MOMENTARY)) + .tag(7).TOG_STYLE(tog7).enabled(t_ok).button (UNLD_CONT_POS, GET_TEXT_F(MSG_CONTINUOUS)) + .tag(8).TOG_STYLE(tog8).enabled(t_ok).button (LOAD_CONT_POS, GET_TEXT_F(MSG_CONTINUOUS)) + .tag(1).colors(action_btn) .button (BACK_POS, GET_TEXT_F(MSG_BACK)); + } +} + +uint8_t ChangeFilamentScreen::getSoftenTemp() { + switch (screen_data.ChangeFilament.t_tag) { + case 2: return LOW_TEMP; + case 3: return MED_TEMP; + case 4: return HIGH_TEMP; + default: return EXTRUDE_MINTEMP; + } +} + +ExtUI::extruder_t ChangeFilamentScreen::getExtruder() { + switch (screen_data.ChangeFilament.e_tag) { + case 13: return ExtUI::E3; + case 12: return ExtUI::E2; + case 11: return ExtUI::E1; + default: return ExtUI::E0; + } +} + +void ChangeFilamentScreen::doPurge() { + #if FILAMENT_UNLOAD_PURGE_LENGTH > 0 + constexpr float purge_distance_mm = FILAMENT_UNLOAD_PURGE_LENGTH; + if (screen_data.ChangeFilament.need_purge) { + screen_data.ChangeFilament.need_purge = false; + MoveAxisScreen::setManualFeedrate(getExtruder(), purge_distance_mm); + ExtUI::setAxisPosition_mm(ExtUI::getAxisPosition_mm(getExtruder()) + purge_distance_mm, getExtruder()); + } + #endif +} + +bool ChangeFilamentScreen::onTouchStart(uint8_t tag) { + // Make the Momentary and Continuous buttons slightly more responsive + switch (tag) { + case 5: case 6: case 7: case 8: + #if FILAMENT_UNLOAD_PURGE_LENGTH > 0 + if (tag == 5 || tag == 7) doPurge(); + #endif + return ChangeFilamentScreen::onTouchHeld(tag); + default: + return false; + } +} + +bool ChangeFilamentScreen::onTouchEnd(uint8_t tag) { + using namespace ExtUI; + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + case 2: + case 3: + case 4: + // Change temperature + screen_data.ChangeFilament.t_tag = tag; + setTargetTemp_celsius(getSoftenTemp(), getExtruder()); + break; + case 7: + screen_data.ChangeFilament.repeat_tag = (screen_data.ChangeFilament.repeat_tag == 7) ? 0 : 7; + break; + case 8: + screen_data.ChangeFilament.repeat_tag = (screen_data.ChangeFilament.repeat_tag == 8) ? 0 : 8; + break; + case 10: + case 11: + // Change extruder + screen_data.ChangeFilament.e_tag = tag; + screen_data.ChangeFilament.t_tag = 0; + screen_data.ChangeFilament.repeat_tag = 0; + #if FILAMENT_UNLOAD_PURGE_LENGTH > 0 + screen_data.ChangeFilament.need_purge = true; + #endif + setActiveTool(getExtruder(), true); + break; + case 15: GOTO_SCREEN(TemperatureScreen); break; + } + return true; +} + +bool ChangeFilamentScreen::onTouchHeld(uint8_t tag) { + if (ExtUI::isMoving()) return false; // Don't allow moves to accumulate + constexpr float increment = 1; + #define UI_INCREMENT_AXIS(axis) UI_INCREMENT(AxisPosition_mm, axis); + #define UI_DECREMENT_AXIS(axis) UI_DECREMENT(AxisPosition_mm, axis); + switch (tag) { + case 5: case 7: UI_DECREMENT_AXIS(getExtruder()); break; + case 6: case 8: UI_INCREMENT_AXIS(getExtruder()); break; + default: return false; + } + #undef UI_DECREMENT_AXIS + #undef UI_INCREMENT_AXIS + return false; +} + +void ChangeFilamentScreen::onIdle() { + reset_menu_timeout(); + if (screen_data.ChangeFilament.repeat_tag) onTouchHeld(screen_data.ChangeFilament.repeat_tag); + if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) { + onRefresh(); + refresh_timer.start(); + } + BaseScreen::onIdle(); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_advanced_settings_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_advanced_settings_menu.cpp new file mode 100644 index 0000000..656bf1d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_advanced_settings_menu.cpp @@ -0,0 +1,102 @@ +/***************************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +#define GRID_ROWS 4 +#define GRID_COLS 3 +#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 CASE_LIGHT_POS BTN_POS(1,4), BTN_SIZE(1,1) +#define RESTORE_DEFAULTS_POS BTN_POS(2,4), BTN_SIZE(1,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_VELOCITY)) + .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)) + .enabled(ENABLED(CASE_LIGHT_ENABLE)) + .tag(11).button(CASE_LIGHT_POS, GET_TEXT_F(MSG_CASE_LIGHT)) + .tag(12).button(RESTORE_DEFAULTS_POS, GET_TEXT_F(MSG_RESTORE_DEFAULTS)) + .colors(action_btn) + .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK)); + } +} + +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; + #if ENABLED(CASE_LIGHT_ENABLE) + case 11: GOTO_SCREEN(CaseLightScreen); break; + #endif + case 12: GOTO_SCREEN(RestoreFailsafeDialogBox); LockScreen::check_passcode(); break; + default: return false; + } + return true; +} +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_load_chocolate.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_load_chocolate.cpp new file mode 100644 index 0000000..36dc340 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_load_chocolate.cpp @@ -0,0 +1,101 @@ +/************************************ + * cocoa_press_unload_cartridge.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) && ENABLED(TOUCH_UI_COCOA_PRESS) + +#include "screens.h" +#include "screen_data.h" + +using namespace ExtUI; +using namespace FTDI; +using namespace Theme; + +#define GRID_COLS 2 +#define GRID_ROWS 6 + +#define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1) +#define DESCRIPTION_POS BTN_POS(1,2), BTN_SIZE(2,3) +#define CARTRIDGE_OUT_BTN_POS BTN_POS(1,5), BTN_SIZE(1,1) +#define CARTRIDGE_IN_BTN_POS BTN_POS(2,5), BTN_SIZE(1,1) +#define BACK_BTN_POS BTN_POS(1,6), BTN_SIZE(2,1) + +void LoadChocolateScreen::onRedraw(draw_mode_t what) { + CommandProcessor cmd; + + if (what & BACKGROUND) { + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0) + .font(font_large) + .text(TITLE_POS, GET_TEXT_F(MSG_LOAD_CHOCOLATE)); + draw_text_box(cmd, DESCRIPTION_POS, F( + "Drop your chocolate refill into the cartridge. " + "Press and hold the Cartridge Out button until " + "the plunger adapter is visible at the bottom of " + "the extruder. Securely attach a red plunger to " + "the plunger adapter and load the cartridge onto " + "the plunger. Press and hold Cartridge In button " + "until cartridge is fully loaded into the extruder, " + "and use the buttons to help follow the locking path " + "to lock"), + OPT_CENTERY, font_medium); + } + + if (what & FOREGROUND) { + cmd.font(font_medium) + .colors(normal_btn) + .tag(2).button(CARTRIDGE_OUT_BTN_POS, GET_TEXT_F(MSG_CARTRIDGE_OUT)) + .tag(3).button(CARTRIDGE_IN_BTN_POS, GET_TEXT_F(MSG_CARTRIDGE_IN)) + .colors(action_btn) + .tag(1).button(BACK_BTN_POS, GET_TEXT_F(MSG_BACK)); + } +} + +bool LoadChocolateScreen::onTouchEnd(uint8_t tag) { + using namespace ExtUI; + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + } + return true; +} + +bool LoadChocolateScreen::onTouchHeld(uint8_t tag) { + if (ExtUI::isMoving()) return false; // Don't allow moves to accumulate + constexpr float increment = 0.25; + MoveAxisScreen::setManualFeedrate(E0, 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: UI_DECREMENT_AXIS(E0); break; + case 3: UI_INCREMENT_AXIS(E0); break; + default: return false; + } + #undef UI_DECREMENT_AXIS + #undef UI_INCREMENT_AXIS + return false; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_main_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_main_menu.cpp new file mode 100644 index 0000000..9c8ad06 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_main_menu.cpp @@ -0,0 +1,89 @@ +/***************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +#define GRID_ROWS 4 +#define GRID_COLS 2 + +#define MOVE_XYZ_POS BTN_POS(1,1), BTN_SIZE(1,1) +#define TEMPERATURE_POS BTN_POS(2,1), BTN_SIZE(1,1) +#define ZPROBE_ZOFFSET_POS BTN_POS(1,2), 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 ADVANCED_SETTINGS_POS BTN_POS(2,3), BTN_SIZE(1,1) +#define ABOUT_PRINTER_POS BTN_POS(1,4), BTN_SIZE(1,1) +#define BACK_POS BTN_POS(2,4), BTN_SIZE(1,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(ADVANCED_SETTINGS_POS, GET_TEXT_F(MSG_ADVANCED_SETTINGS)) + .tag(8).button(ABOUT_PRINTER_POS, GET_TEXT_F(MSG_INFO_MENU)) + .colors(action_btn) + .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK)); + } +} + +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(AdvancedSettingsMenu); break; + case 8: GOTO_SCREEN(AboutScreen); break; + default: + return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_e_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_e_screen.cpp new file mode 100644 index 0000000..61411af --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_e_screen.cpp @@ -0,0 +1,62 @@ +/********************************* + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace ExtUI; + +void MoveEScreen::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_E_MOVE)); + w.color(Theme::e_axis); + #if EXTRUDERS == 1 + w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E), screen_data.MoveAxis.e_rel[0], canMove(E0)); + #elif HAS_MULTI_EXTRUDER + w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E1), screen_data.MoveAxis.e_rel[0], canMove(E0)); + w.adjuster( 10, GET_TEXT_F(MSG_AXIS_E2), screen_data.MoveAxis.e_rel[1], canMove(E1)); + #if EXTRUDERS > 2 + w.adjuster( 12, GET_TEXT_F(MSG_AXIS_E3), screen_data.MoveAxis.e_rel[2], canMove(E2)); + #endif + #if EXTRUDERS > 3 + w.adjuster( 14, GET_TEXT_F(MSG_AXIS_E4), screen_data.MoveAxis.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 // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_xyz_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_xyz_screen.cpp new file mode 100644 index 0000000..52a7044 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_move_xyz_screen.cpp @@ -0,0 +1,53 @@ +/************************************ + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" +#include "screen_data.h" + +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 // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_menu.cpp new file mode 100644 index 0000000..99c0c1b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_menu.cpp @@ -0,0 +1,113 @@ +/******************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +#define GRID_ROWS 5 +#define GRID_COLS 2 + +void PreheatMenu::onRedraw(draw_mode_t what) { + const int16_t w = 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_INTERNAL)); + if (has_extra_heater()) { + cmd.text( BTN_POS(2,1), w, h, GET_TEXT_F(MSG_EXTERNAL)); + } + } + + 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 (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")); + } + cmd.colors(action_btn) + .tag(1) .button(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_BACK)); + } +} + +bool PreheatMenu::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + case 2: + #ifdef COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_INT_SCRIPT + injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_INT_SCRIPT)); + #endif + GOTO_SCREEN(PreheatTimerScreen); + break; + case 3: + #ifdef COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_INT_SCRIPT + injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_INT_SCRIPT)); + #endif + GOTO_SCREEN(PreheatTimerScreen); + break; + case 4: + #ifdef COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_INT_SCRIPT + injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_INT_SCRIPT)); + #endif + GOTO_SCREEN(PreheatTimerScreen); + break; + case 5: + #ifdef COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_EXT_SCRIPT + injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_DARK_CHOCOLATE_EXT_SCRIPT)); + #endif + GOTO_SCREEN(PreheatTimerScreen); + break; + case 6: + #ifdef COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_EXT_SCRIPT + injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_MILK_CHOCOLATE_EXT_SCRIPT)); + #endif + GOTO_SCREEN(PreheatTimerScreen); + break; + case 7: + #ifdef COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_EXT_SCRIPT + injectCommands_P(PSTR(COCOA_PRESS_PREHEAT_WHITE_CHOCOLATE_EXT_SCRIPT)); + #endif + GOTO_SCREEN(PreheatTimerScreen); + break; + default: return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_screen.cpp new file mode 100644 index 0000000..c9caef6 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_preheat_screen.cpp @@ -0,0 +1,172 @@ +/**************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" +#include "screen_data.h" + +#include "../ftdi_eve_lib/extras/circular_progress.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +#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() - screen_data.PreheatTimer.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_BACK)); + } +} + +void PreheatTimerScreen::draw_adjuster(draw_mode_t what, uint8_t tag, progmem_str label, float value, int16_t x, int16_t y, int16_t w, int16_t h) { + #define SUB_COLS 9 + #define SUB_ROWS 2 + #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) + + 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() { + screen_data.PreheatTimer.start_ms = millis(); +} + +void PreheatTimerScreen::onRedraw(draw_mode_t what) { + draw_message(what); + draw_time_remaining(what); + draw_interaction_buttons(what); + draw_adjuster(what, 1, GET_TEXT_F(MSG_NOZZLE), getTargetTemp_celsius(E0), NOZZLE_ADJ_POS); + draw_adjuster(what, 3, GET_TEXT_F(MSG_BODY), getTargetTemp_celsius(E1), BODY_ADJ_POS); + draw_adjuster(what, 5, GET_TEXT_F(MSG_CHAMBER), getTargetTemp_celsius(CHAMBER), CHAMBER_ADJ_POS); +} + +bool PreheatTimerScreen::onTouchHeld(uint8_t tag) { + const float increment = (tag == 5 || tag == 6) ? 1 : 0.1; + switch (tag) { + case 1: UI_DECREMENT(TargetTemp_celsius, E0); break; + case 2: UI_INCREMENT(TargetTemp_celsius, E0); break; + case 3: UI_DECREMENT(TargetTemp_celsius, E1); break; + case 4: UI_INCREMENT(TargetTemp_celsius, E1); break; + case 5: UI_DECREMENT(TargetTemp_celsius, CHAMBER); break; + case 6: 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: break; + } + 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 // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_status_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_status_screen.cpp new file mode 100644 index 0000000..d9881d7 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" + +#include "../ftdi_eve_lib/extras/poly_ui.h" + +#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(bg_color)); + + cmd.cmd(COLOR_RGB(fluid_rgb)); + cmd.font(font_medium); + + 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); + + 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 NUM_SERVOS < 2 + // Note, this requires a new pin 108 to be added to to access ADC9 + // "ArduinoAddons/arduino-1.8.5/packages/ultimachine/hardware/sam/1.6.9-b/variants/archim/variant.cpp" + const int val = analogRead(108); + const float fill_level = float(val) / 1024; + #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); + + ui.bounds(POLY(unload_cartridge_btn), x, y, h, v); + + cmd.font(font_medium).colors(normal_btn); + + ui.bounds(POLY(unload_cartridge_btn), x, y, h, v); + cmd.tag(1).button(x, y, h, v, GET_TEXT_F(MSG_UNLOAD_CARTRIDGE)); + + ui.bounds(POLY(load_chocolate_btn), x, y, h, v); + cmd.tag(2).button(x, y, h, v, GET_TEXT_F(MSG_LOAD_CHOCOLATE)); + + 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: GOTO_SCREEN(UnloadCartridgeScreen); 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 host_action_pause(); + #endif + GOTO_SCREEN(StatusScreen); + break; + case 6: + sound.play(twinkle, PLAY_ASYNCHRONOUS); + if (ExtUI::isPrintingFromMedia()) + ExtUI::resumePrint(); + #ifdef ACTION_ON_RESUME + else host_action_resume(); + #endif + GOTO_SCREEN(StatusScreen); + break; + case 7: + GOTO_SCREEN(ConfirmAbortPrintDialogBox); + current_screen.forget(); + PUSH_SCREEN(StatusScreen); + break; + case 9: GOTO_SCREEN(FilesScreen); 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()) { + increment = 0.05; + MoveAxisScreen::setManualFeedrate(E0, increment); + UI_INCREMENT(AxisPosition_mm, E0); + current_screen.onRefresh(); + } + return false; +} + +void StatusScreen::setStatusMessage(progmem_str) { +} + +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(); + } +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_ui.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_ui.h new file mode 100644 index 0000000..5cbaced --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_ui.h @@ -0,0 +1,54 @@ + +/**************************************************************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/** + * 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 unload_cartridge_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 extrude_btn[] = {0xC859, 0xDD2B, 0xF5AE, 0xDD2B, 0xF5AE, 0xEFFE, 0xC859, 0xEFFE, 0xC859, 0xDD2B}; +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}; diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_unload_cartridge.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_unload_cartridge.cpp new file mode 100644 index 0000000..2e71093 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/cocoa_press_unload_cartridge.cpp @@ -0,0 +1,101 @@ +/************************************ + * cocoa_press_unload_cartridge.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) && ENABLED(TOUCH_UI_COCOA_PRESS) + +#include "screens.h" +#include "screen_data.h" + +using namespace ExtUI; +using namespace FTDI; +using namespace Theme; + +#define GRID_COLS 2 +#define GRID_ROWS 6 + +#define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1) +#define DESCRIPTION_POS BTN_POS(1,2), BTN_SIZE(2,3) +#define CARTRIDGE_OUT_BTN_POS BTN_POS(1,5), BTN_SIZE(1,1) +#define CARTRIDGE_IN_BTN_POS BTN_POS(2,5), BTN_SIZE(1,1) +#define BACK_BTN_POS BTN_POS(1,6), BTN_SIZE(2,1) + +void UnloadCartridgeScreen::onRedraw(draw_mode_t what) { + CommandProcessor cmd; + + if (what & BACKGROUND) { + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0) + .font(font_large) + .text(TITLE_POS, GET_TEXT_F(MSG_UNLOAD_CARTRIDGE)); + draw_text_box(cmd, DESCRIPTION_POS, F( + "Press and hold the buttons below to help " + "you unlock the cartridge. After unlocking, " + "press and hold the Cartridge Out button " + "until the cartridge is sticking out of the " + "extruder enough to grip and remove. After " + "removing the cartridge, continue holding the " + "Cartridge Out button until the plunger adapter is " + "visible at the bottom of the extruder." + ), + OPT_CENTERY, font_medium); + } + + if (what & FOREGROUND) { + cmd.font(font_medium) + .colors(normal_btn) + .tag(2).button(CARTRIDGE_OUT_BTN_POS, GET_TEXT_F(MSG_CARTRIDGE_OUT)) + .tag(3).button(CARTRIDGE_IN_BTN_POS, GET_TEXT_F(MSG_CARTRIDGE_IN)) + .colors(action_btn) + .tag(1).button(BACK_BTN_POS, GET_TEXT_F(MSG_BACK)); + } +} + +bool UnloadCartridgeScreen::onTouchEnd(uint8_t tag) { + using namespace ExtUI; + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + } + return true; +} + +bool UnloadCartridgeScreen::onTouchHeld(uint8_t tag) { + if (ExtUI::isMoving()) return false; // Don't allow moves to accumulate + constexpr float increment = 0.25; + MoveAxisScreen::setManualFeedrate(E0, 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: UI_DECREMENT_AXIS(E0); break; + case 3: UI_INCREMENT_AXIS(E0); break; + default: return false; + } + #undef UI_DECREMENT_AXIS + #undef UI_INCREMENT_AXIS + return false; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_abort_print_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_abort_print_dialog_box.cpp new file mode 100644 index 0000000..528d93d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_abort_print_dialog_box.cpp @@ -0,0 +1,53 @@ +/************************************** + * confirm_abort_print_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +#include "../../../../../feature/host_actions.h" + +using namespace ExtUI; + +void ConfirmAbortPrintDialogBox::onRedraw(draw_mode_t) { + drawMessage(GET_TEXT_F(MSG_ABORT_WARNING)); + drawYesNoButtons(); +} + +bool ConfirmAbortPrintDialogBox::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: + GOTO_PREVIOUS(); + if (ExtUI::isPrintingFromMedia()) + ExtUI::stopPrint(); + #ifdef ACTION_ON_CANCEL + else host_action_cancel(); + #endif + return true; + default: + return DialogBoxBaseClass::onTouchEnd(tag); + } +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_auto_calibration_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_auto_calibration_dialog_box.cpp new file mode 100644 index 0000000..f7c8567 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_auto_calibration_dialog_box.cpp @@ -0,0 +1,48 @@ +/******************************************* + * confirm_auto_calibration_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, CALIBRATION_GCODE) + +#include "screens.h" + +using namespace ExtUI; +using namespace Theme; + +void ConfirmAutoCalibrationDialogBox::onRedraw(draw_mode_t) { + drawMessage(GET_TEXT_F(MSG_CALIBRATION_WARNING)); + drawYesNoButtons(); +} + +bool ConfirmAutoCalibrationDialogBox::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: + GOTO_SCREEN(StatusScreen); + injectCommands_P(PSTR("G425")); + return true; + default: + return DialogBoxBaseClass::onTouchEnd(tag); + } +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_erase_flash_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_erase_flash_dialog_box.cpp new file mode 100644 index 0000000..baf5959 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_erase_flash_dialog_box.cpp @@ -0,0 +1,54 @@ +/************************************** + * confirm_erase_flash_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU) + +#include "screens.h" + +#include "../archim2-flash/flash_storage.h" + +using namespace FTDI; + +void ConfirmEraseFlashDialogBox::onRedraw(draw_mode_t) { + drawMessage(GET_TEXT_F(MSG_ERASE_FLASH_WARNING)); + drawYesNoButtons(); +} + +bool ConfirmEraseFlashDialogBox::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: + SpinnerDialogBox::show(GET_TEXT_F(MSG_ERASING)); + UIFlashStorage::format_flash(); + SpinnerDialogBox::hide(); + AlertDialogBox::show(GET_TEXT_F(MSG_ERASED)); + // Remove ConfirmEraseFlashDialogBox from the stack + // so the alert box doesn't return to me. + current_screen.forget(); + return true; + default: + return DialogBoxBaseClass::onTouchEnd(tag); + } +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_start_print_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_start_print_dialog_box.cpp new file mode 100644 index 0000000..eeca88f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_start_print_dialog_box.cpp @@ -0,0 +1,65 @@ +/************************************** + * confirm_start_print_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace Theme; +using namespace ExtUI; + +void ConfirmStartPrintDialogBox::onRedraw(draw_mode_t) { + const char *filename = getLongFilename(); + char buffer[strlen_P(GET_TEXT(MSG_START_PRINT_CONFIRMATION)) + strlen(filename) + 1]; + sprintf_P(buffer, GET_TEXT(MSG_START_PRINT_CONFIRMATION), filename); + drawMessage((const char *)buffer); + drawYesNoButtons(1); +} + +bool ConfirmStartPrintDialogBox::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: + printFile(getShortFilename()); + StatusScreen::setStatusMessage(GET_TEXT_F(MSG_PRINT_STARTING)); + GOTO_SCREEN(StatusScreen); + return true; + case 2: GOTO_PREVIOUS(); return true; + default: return false; + } +} + +const char *ConfirmStartPrintDialogBox::getFilename(bool longName) { + FileList files; + files.seek(screen_data.ConfirmStartPrintDialog.file_index, true); + return longName ? files.longFilename() : files.shortFilename(); +} + +void ConfirmStartPrintDialogBox::show(uint8_t file_index) { + screen_data.ConfirmStartPrintDialog.file_index = file_index; + GOTO_SCREEN(ConfirmStartPrintDialogBox); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_user_request_alert_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_user_request_alert_box.cpp new file mode 100644 index 0000000..59e1c82 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/confirm_user_request_alert_box.cpp @@ -0,0 +1,66 @@ +/************************************** + * confirm_user_request_alert_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; + +void ConfirmUserRequestAlertBox::onRedraw(draw_mode_t mode) { + AlertDialogBox::onRedraw(mode); // Required for the GOTO_SCREEN function to work +} + +bool ConfirmUserRequestAlertBox::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: + if (ExtUI::isPrintingPaused()) { + // The TuneMenu will call ExtUI::setUserConfirmed() + GOTO_SCREEN(TuneMenu); + current_screen.forget(); + } + else { + ExtUI::setUserConfirmed(); + GOTO_PREVIOUS(); + } + return true; + case 2: GOTO_PREVIOUS(); return true; + default: return false; + } +} + +void ConfirmUserRequestAlertBox::show(const char* msg) { + drawMessage(msg); + storeBackground(); + screen_data.AlertDialog.isError = false; + GOTO_SCREEN(ConfirmUserRequestAlertBox); +} + +void ConfirmUserRequestAlertBox::hide() { + if (AT_SCREEN(ConfirmUserRequestAlertBox)) + GOTO_PREVIOUS(); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/custom_user_menus.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/custom_user_menus.cpp new file mode 100644 index 0000000..20f90d5 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/custom_user_menus.cpp @@ -0,0 +1,215 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, CUSTOM_USER_MENUS) && NONE(TOUCH_UI_LULZBOT_BIO, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +#define _ITEM_TAG(N) (10+N) +#define _USER_DESC(N) USER_DESC_##N +#define _USER_GCODE(N) USER_GCODE_##N +#define _USER_ITEM(N) .tag(_ITEM_TAG(N)).button(USER_ITEM_POS(N), _USER_DESC(N)) +#define _USER_ACTION(N) case _ITEM_TAG(N): injectCommands_P(PSTR(_USER_GCODE(N))); TERN_(USER_SCRIPT_RETURN, GOTO_SCREEN(StatusScreen)); break; + +#define _HAS_1(N) (defined(USER_DESC_##N) && defined(USER_GCODE_##N)) +#define HAS_USER_ITEM(V...) DO(HAS,||,V) + +void CustomUserMenus::onRedraw(draw_mode_t what) { + if (what & BACKGROUND) { + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color)) + .cmd(CLEAR(true, true, true)); + } + + #if HAS_USER_ITEM(16, 17, 18, 19, 20) + #define _MORE_THAN_FIFTEEN 1 + #else + #define _MORE_THAN_FIFTEEN 0 + #endif + #if _MORE_THAN_FIFTEEN || HAS_USER_ITEM(11, 12, 13, 14, 15) + #define _MORE_THAN_TEN 1 + #else + #define _MORE_THAN_TEN 0 + #endif + + #if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_ROWS 11 + #define GRID_COLS (1 + _MORE_THAN_TEN) + #define USER_ITEM_POS(N) BTN_POS((1+((N-1)/10)), ((N-1) % 10 + 1)), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(1,11), BTN_SIZE(1,1) + #else + #if _MORE_THAN_TEN || HAS_USER_ITEM(6, 7, 8, 9, 10) + #define _MORE_THAN_FIVE 1 + #else + #define _MORE_THAN_FIVE 0 + #endif + #define GRID_ROWS 6 + #define GRID_COLS (1 + _MORE_THAN_FIVE + _MORE_THAN_TEN + _MORE_THAN_FIFTEEN) + #define USER_ITEM_POS(N) BTN_POS((1+((N-1)/5)), ((N-1) % 5 + 1)), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(1,6), BTN_SIZE(GRID_COLS,1) + #endif + + if (what & FOREGROUND) { + CommandProcessor cmd; + cmd.colors(normal_btn) + .font(Theme::font_medium) + #if HAS_USER_ITEM(1) + _USER_ITEM(1) + #endif + #if HAS_USER_ITEM(2) + _USER_ITEM(2) + #endif + #if HAS_USER_ITEM(3) + _USER_ITEM(3) + #endif + #if HAS_USER_ITEM(4) + _USER_ITEM(4) + #endif + #if HAS_USER_ITEM(5) + _USER_ITEM(5) + #endif + #if HAS_USER_ITEM(6) + _USER_ITEM(6) + #endif + #if HAS_USER_ITEM(7) + _USER_ITEM(7) + #endif + #if HAS_USER_ITEM(8) + _USER_ITEM(8) + #endif + #if HAS_USER_ITEM(9) + _USER_ITEM(9) + #endif + #if HAS_USER_ITEM(10) + _USER_ITEM(10) + #endif + #if HAS_USER_ITEM(11) + _USER_ITEM(11) + #endif + #if HAS_USER_ITEM(12) + _USER_ITEM(12) + #endif + #if HAS_USER_ITEM(13) + _USER_ITEM(13) + #endif + #if HAS_USER_ITEM(14) + _USER_ITEM(14) + #endif + #if HAS_USER_ITEM(15) + _USER_ITEM(15) + #endif + #if HAS_USER_ITEM(16) + _USER_ITEM(16) + #endif + #if HAS_USER_ITEM(17) + _USER_ITEM(17) + #endif + #if HAS_USER_ITEM(18) + _USER_ITEM(18) + #endif + #if HAS_USER_ITEM(19) + _USER_ITEM(19) + #endif + #if HAS_USER_ITEM(20) + _USER_ITEM(20) + #endif + .colors(action_btn) + .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK)); + } +} + +bool CustomUserMenus::onTouchEnd(uint8_t tag) { + switch (tag) { + #if HAS_USER_ITEM(1) + _USER_ACTION(1) + #endif + #if HAS_USER_ITEM(2) + _USER_ACTION(2) + #endif + #if HAS_USER_ITEM(3) + _USER_ACTION(3) + #endif + #if HAS_USER_ITEM(4) + _USER_ACTION(4) + #endif + #if HAS_USER_ITEM(5) + _USER_ACTION(5) + #endif + #if HAS_USER_ITEM(6) + _USER_ACTION(6) + #endif + #if HAS_USER_ITEM(7) + _USER_ACTION(7) + #endif + #if HAS_USER_ITEM(8) + _USER_ACTION(8) + #endif + #if HAS_USER_ITEM(9) + _USER_ACTION(9) + #endif + #if HAS_USER_ITEM(10) + _USER_ACTION(10) + #endif + #if HAS_USER_ITEM(11) + _USER_ACTION(11) + #endif + #if HAS_USER_ITEM(12) + _USER_ACTION(12) + #endif + #if HAS_USER_ITEM(13) + _USER_ACTION(13) + #endif + #if HAS_USER_ITEM(14) + _USER_ACTION(14) + #endif + #if HAS_USER_ITEM(15) + _USER_ACTION(15) + #endif + #if HAS_USER_ITEM(16) + _USER_ACTION(16) + #endif + #if HAS_USER_ITEM(17) + _USER_ACTION(17) + #endif + #if HAS_USER_ITEM(18) + _USER_ACTION(18) + #endif + #if HAS_USER_ITEM(19) + _USER_ACTION(19) + #endif + #if HAS_USER_ITEM(20) + _USER_ACTION(20) + #endif + + case 1: GOTO_PREVIOUS(); break; + default: return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE && CUSTOM_USER_MENUS && !TOUCH_UI_LULZBOT_BIO && !TOUCH_UI_COCOA_PRESS diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/default_acceleration_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/default_acceleration_screen.cpp new file mode 100644 index 0000000..de617d4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/default_acceleration_screen.cpp @@ -0,0 +1,63 @@ +/*********************************** + * default_acceleration_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void DefaultAccelerationScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(0); + w.units(GET_TEXT_F(MSG_UNITS_MM_S2)); + w.heading( GET_TEXT_F(MSG_ACCELERATION)); + w.color(other); + w.adjuster( 2, GET_TEXT_F(MSG_ACCEL_PRINTING), getPrintingAcceleration_mm_s2() ); + w.adjuster( 4, GET_TEXT_F(MSG_ACCEL_TRAVEL), getTravelAcceleration_mm_s2() ); + w.adjuster( 6, GET_TEXT_F(MSG_ACCEL_RETRACT), getRetractAcceleration_mm_s2() ); + w.increments(); + w.button( 8, GET_TEXT_F(MSG_SET_MAXIMUM)); +} + +bool DefaultAccelerationScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(PrintingAcceleration_mm_s2); break; + case 3: UI_INCREMENT(PrintingAcceleration_mm_s2); break; + case 4: UI_DECREMENT(TravelAcceleration_mm_s2); break; + case 5: UI_INCREMENT(TravelAcceleration_mm_s2); break; + case 6: UI_DECREMENT(RetractAcceleration_mm_s2); break; + case 7: UI_INCREMENT(RetractAcceleration_mm_s2); break; + case 8: GOTO_SCREEN(MaxAccelerationScreen); break; + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/developer_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/developer_menu.cpp new file mode 100644 index 0000000..9df060a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/developer_menu.cpp @@ -0,0 +1,150 @@ +/********************** + * developer_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU) + +#include "screens.h" + +#include "../archim2-flash/flash_storage.h" + +using namespace FTDI; +using namespace Theme; + +void DeveloperMenu::onRedraw(draw_mode_t what) { + if (what & BACKGROUND) { + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .font(font_medium) + .tag(0); + + #ifdef SPI_FLASH_SS + constexpr bool has_flash = true; + #else + constexpr bool has_flash = false; + #endif + + #if ENABLED(SDSUPPORT) + constexpr bool has_media = true; + #else + constexpr bool has_media = false; + #endif + + cmd.cmd(COLOR_RGB(bg_text_enabled)); + #if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_ROWS 10 + #define GRID_COLS 1 + cmd.font(font_large) .text ( BTN_POS(1,1), BTN_SIZE(1,1), F("Developer Menu")) + .colors(normal_btn) + .tag(2).font(font_medium) .button(BTN_POS(1,2), BTN_SIZE(1,1), F("Show All Widgets")) + .tag(3) .button(BTN_POS(1,3), BTN_SIZE(1,1), F("Stress Test")) + .tag(4) .button(BTN_POS(1,4), BTN_SIZE(1,1), F("Show Touch Registers")) + .tag(5) .button(BTN_POS(1,5), BTN_SIZE(1,1), F("Play Song")) + .tag(6).enabled(has_media).button(BTN_POS(1,6), BTN_SIZE(1,1), F("Play Video from Media")) + .tag(7).enabled(has_flash).button(BTN_POS(1,7), BTN_SIZE(1,1), F("Play Video from SPI Flash")) + .tag(8).enabled(has_flash).button(BTN_POS(1,8), BTN_SIZE(1,1), F("Load Video to SPI Flash")) + .tag(9).enabled(has_flash).button(BTN_POS(1,9), BTN_SIZE(1,1), F("Erase SPI Flash")) + + .tag(1).colors(action_btn) + .button(BTN_POS(1,10), BTN_SIZE(1,1), F("Back")); + #else + #define GRID_ROWS 6 + #define GRID_COLS 2 + cmd.font(font_medium) .text ( BTN_POS(1,1), BTN_SIZE(2,1), F("Developer Menu")) + .colors(normal_btn) + .tag(2).font(font_small) .button(BTN_POS(1,2), BTN_SIZE(1,1), F("Show All Widgets")) + .tag(3) .button(BTN_POS(1,3), BTN_SIZE(1,1), F("Show Touch Registers")) + .tag(9) .button(BTN_POS(1,4), BTN_SIZE(1,1), F("Show Pin States")) + .tag(4) .button(BTN_POS(1,5), BTN_SIZE(1,1), F("Play Song")) + .tag(5).enabled(has_media).button(BTN_POS(2,2), BTN_SIZE(1,1), F("Play Video from Media")) + .tag(6).enabled(has_flash).button(BTN_POS(2,3), BTN_SIZE(1,1), F("Play Video from SPI Flash")) + .tag(7).enabled(has_flash).button(BTN_POS(2,4), BTN_SIZE(1,1), F("Load Video to SPI Flash")) + .tag(8).enabled(has_flash).button(BTN_POS(2,5), BTN_SIZE(1,1), F("Erase SPI Flash")) + .tag(1).colors(action_btn) + .button(BTN_POS(1,6), BTN_SIZE(2,1), F("Back")); + #endif + } +} + +bool DeveloperMenu::onTouchEnd(uint8_t tag) { + using namespace Theme; + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + case 2: GOTO_SCREEN(WidgetsScreen); break; + case 3: + PUSH_SCREEN(StressTestScreen); + AlertDialogBox::show(F("Please do not run this test unattended as it may cause your printer to malfunction.")); + current_screen.forget(); + break; + case 4: GOTO_SCREEN(TouchRegistersScreen); break; + case 5: sound.play(js_bach_joy, PLAY_ASYNCHRONOUS); break; + #if ENABLED(SDSUPPORT) + case 6: + if (!MediaPlayerScreen::playCardMedia()) + AlertDialogBox::showError(F("Cannot open STARTUP.AVI")); + break; + #endif + #ifdef SPI_FLASH_SS + case 7: + if (!MediaPlayerScreen::playBootMedia()) + AlertDialogBox::showError(F("No boot media available")); + break; + case 8: + { + SpinnerDialogBox::show(F("Saving...")); + UIFlashStorage::error_t res = UIFlashStorage::write_media_file(F("STARTUP.AVI")); + SpinnerDialogBox::hide(); + reset_menu_timeout(); + switch (res) { + case UIFlashStorage::SUCCESS: + AlertDialogBox::show(F("File copied!")); + break; + + case UIFlashStorage::READ_ERROR: + AlertDialogBox::showError(F("Failed to read file")); + break; + + case UIFlashStorage::VERIFY_ERROR: + AlertDialogBox::showError(F("Failed to verify file")); + break; + + case UIFlashStorage::FILE_NOT_FOUND: + AlertDialogBox::showError(F("Cannot open STARTUP.AVI")); + break; + + case UIFlashStorage::WOULD_OVERWRITE: + AlertDialogBox::showError(F("Cannot overwrite existing media.")); + break; + } + break; + } + case 9: GOTO_SCREEN(ConfirmEraseFlashDialogBox); break; + #endif + case 10: GOTO_SCREEN(EndstopStatesScreen); break; + default: return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/dialog_box_base_class.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/dialog_box_base_class.cpp new file mode 100644 index 0000000..6fe7be4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/dialog_box_base_class.cpp @@ -0,0 +1,87 @@ +/***************************** + * dialog_box_base_class.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +#define GRID_COLS 2 +#define GRID_ROWS 8 + +template<typename T> +void DialogBoxBaseClass::drawMessage(const T message, int16_t font) { + CommandProcessor cmd; + cmd.cmd(CMD_DLSTART) + .cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0); + draw_text_box(cmd, BTN_POS(1,1), BTN_SIZE(2,3), message, OPT_CENTER, font ? font : font_large); + cmd.colors(normal_btn); +} + +template void DialogBoxBaseClass::drawMessage(const char *, int16_t font); +template void DialogBoxBaseClass::drawMessage(progmem_str, int16_t font); + +void DialogBoxBaseClass::drawYesNoButtons(uint8_t default_btn) { + CommandProcessor cmd; + cmd.font(font_medium) + .colors(default_btn == 1 ? action_btn : normal_btn).tag(1).button(BTN_POS(1,8), BTN_SIZE(1,1), GET_TEXT_F(MSG_YES)) + .colors(default_btn == 2 ? action_btn : normal_btn).tag(2).button(BTN_POS(2,8), BTN_SIZE(1,1), GET_TEXT_F(MSG_NO)); +} + +void DialogBoxBaseClass::drawOkayButton() { + CommandProcessor cmd; + cmd.font(font_medium) + .tag(1).button(BTN_POS(1,8), BTN_SIZE(2,1), GET_TEXT_F(MSG_BUTTON_OKAY)); +} + +void DialogBoxBaseClass::drawButton(const progmem_str label) { + CommandProcessor cmd; + cmd.font(font_medium) + .tag(1).button(BTN_POS(1,8), BTN_SIZE(2,1), label); +} + +void DialogBoxBaseClass::drawSpinner() { + CommandProcessor cmd; + cmd.cmd(COLOR_RGB(bg_text_enabled)) + .spinner(BTN_POS(1,4), BTN_SIZE(2,3)).execute(); +} + +bool DialogBoxBaseClass::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); return true; + case 2: GOTO_PREVIOUS(); return true; + default: return false; + } +} + +void DialogBoxBaseClass::onIdle() { + reset_menu_timeout(); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/display_tuning_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/display_tuning_screen.cpp new file mode 100644 index 0000000..1a4d9fd --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/display_tuning_screen.cpp @@ -0,0 +1,61 @@ +/***************************** + * display_tuning_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +void DisplayTuningScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(0, BaseNumericAdjustmentScreen::DEFAULT_LOWEST); + w.units(F("")); + w.heading(GET_TEXT_F(MSG_DISPLAY_MENU)); + w.color(other); + w.adjuster( 2, GET_TEXT_F(MSG_H_OFFSET), CLCD::mem_read_16(CLCD::REG::HOFFSET) ); + w.adjuster( 4, GET_TEXT_F(MSG_V_OFFSET), CLCD::mem_read_16(CLCD::REG::VOFFSET) ); + w.increments(); + w.heading( GET_TEXT_F(MSG_TOUCH_SCREEN)); + w.button(6, GET_TEXT_F(MSG_CALIBRATE)); +} + +bool DisplayTuningScreen::onTouchHeld(uint8_t tag) { + #define REG_INCREMENT(a,i) CLCD::mem_write_16(CLCD::REG::a, CLCD::mem_read_16(CLCD::REG::a) + i) + const float increment = getIncrement(); + switch (tag) { + case 2: REG_INCREMENT(HOFFSET, -increment); break; + case 3: REG_INCREMENT(HOFFSET, increment); break; + case 4: REG_INCREMENT(VOFFSET, -increment); break; + case 5: REG_INCREMENT(VOFFSET, increment); break; + case 6: GOTO_SCREEN(TouchCalibrationScreen); break; + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/endstop_state_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/endstop_state_screen.cpp new file mode 100644 index 0000000..a091197 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/endstop_state_screen.cpp @@ -0,0 +1,152 @@ +/**************************** + * endstop_state_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; +using namespace ExtUI; + +void EndstopStatesScreen::onEntry() { + BaseScreen::onEntry(); +} + +void EndstopStatesScreen::onExit() { + BaseScreen::onExit(); +} + +void EndstopStatesScreen::onRedraw(draw_mode_t) { + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(COLOR_RGB(bg_text_enabled)) + .cmd(CLEAR(true,true,true)) + .tag(0); + + #define GRID_ROWS 7 + #define GRID_COLS 6 + + #define PIN_BTN(X,Y,PIN,LABEL) button(BTN_POS(X,Y), BTN_SIZE(2,1), LABEL) + #define PIN_ENABLED(X,Y,LABEL,PIN,INV) cmd.enabled(1).colors(READ(PIN##_PIN) != INV ? action_btn : normal_btn).PIN_BTN(X,Y,PIN,LABEL); + #define PIN_DISABLED(X,Y,LABEL,PIN) cmd.enabled(0).PIN_BTN(X,Y,PIN,LABEL); + + cmd.font( + #if ENABLED(TOUCH_UI_PORTRAIT) + font_large + #else + font_medium + #endif + ) + .text(BTN_POS(1,1), BTN_SIZE(6,1), GET_TEXT_F(MSG_LCD_ENDSTOPS)) + .font(font_tiny); + #if PIN_EXISTS(X_MAX) + PIN_ENABLED (1, 2, PSTR(STR_X_MAX), X_MAX, X_MAX_ENDSTOP_INVERTING) + #else + PIN_DISABLED(1, 2, PSTR(STR_X_MAX), X_MAX) + #endif + #if PIN_EXISTS(Y_MAX) + PIN_ENABLED (3, 2, PSTR(STR_Y_MAX), Y_MAX, Y_MAX_ENDSTOP_INVERTING) + #else + PIN_DISABLED(3, 2, PSTR(STR_Y_MAX), Y_MAX) + #endif + #if PIN_EXISTS(Z_MAX) + PIN_ENABLED (5, 2, PSTR(STR_Z_MAX), Z_MAX, Z_MAX_ENDSTOP_INVERTING) + #else + PIN_DISABLED(5, 2, PSTR(STR_Z_MAX), Z_MAX) + #endif + #if PIN_EXISTS(X_MIN) + PIN_ENABLED (1, 3, PSTR(STR_X_MIN), X_MIN, X_MIN_ENDSTOP_INVERTING) + #else + PIN_DISABLED(1, 3, PSTR(STR_X_MIN), X_MIN) + #endif + #if PIN_EXISTS(Y_MIN) + PIN_ENABLED (3, 3, PSTR(STR_Y_MIN), Y_MIN, Y_MIN_ENDSTOP_INVERTING) + #else + PIN_DISABLED(3, 3, PSTR(STR_Y_MIN), Y_MIN) + #endif + #if PIN_EXISTS(Z_MIN) + PIN_ENABLED (5, 3, PSTR(STR_Z_MIN), Z_MIN, Z_MIN_ENDSTOP_INVERTING) + #else + PIN_DISABLED(5, 3, PSTR(STR_Z_MIN), Z_MIN) + #endif + #if ENABLED(FILAMENT_RUNOUT_SENSOR) && PIN_EXISTS(FIL_RUNOUT) + PIN_ENABLED (1, 4, GET_TEXT_F(MSG_RUNOUT_1), FIL_RUNOUT, FIL_RUNOUT1_STATE) + #else + PIN_DISABLED(1, 4, GET_TEXT_F(MSG_RUNOUT_1), FIL_RUNOUT) + #endif + #if BOTH(HAS_MULTI_EXTRUDER, FILAMENT_RUNOUT_SENSOR) && PIN_EXISTS(FIL_RUNOUT2) + PIN_ENABLED (3, 4, GET_TEXT_F(MSG_RUNOUT_2), FIL_RUNOUT2, FIL_RUNOUT2_STATE) + #else + PIN_DISABLED(3, 4, GET_TEXT_F(MSG_RUNOUT_2), FIL_RUNOUT2) + #endif + #if PIN_EXISTS(Z_MIN_PROBE) + PIN_ENABLED (5, 4, PSTR(STR_Z_PROBE), Z_MIN_PROBE, Z_MIN_PROBE_ENDSTOP_INVERTING) + #else + PIN_DISABLED(5, 4, PSTR(STR_Z_PROBE), Z_MIN_PROBE) + #endif + + #if HAS_SOFTWARE_ENDSTOPS + #undef EDGE_R + #define EDGE_R 30 + cmd.cmd(COLOR_RGB(bg_text_enabled)) + .font(font_small) + .text (BTN_POS(1,5), BTN_SIZE(3,1), GET_TEXT_F(MSG_LCD_SOFT_ENDSTOPS), OPT_RIGHTX | OPT_CENTERY) + .colors(ui_toggle) + .tag(2).toggle2(BTN_POS(4,5), BTN_SIZE(3,1), GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), getSoftEndstopState()); + #undef EDGE_R + #define EDGE_R 0 + #endif + + cmd.font(font_medium) + .colors(action_btn) + .tag(1).button(BTN_POS(1,7), BTN_SIZE(6,1), GET_TEXT_F(MSG_BACK)); + #undef GRID_COLS + #undef GRID_ROWS +} + +bool EndstopStatesScreen::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + #if HAS_SOFTWARE_ENDSTOPS + case 2: setSoftEndstopState(!getSoftEndstopState()); + #endif + default: + return false; + } + return true; +} + +void EndstopStatesScreen::onIdle() { + constexpr uint32_t DIAGNOSTICS_UPDATE_INTERVAL = 100; + + if (refresh_timer.elapsed(DIAGNOSTICS_UPDATE_INTERVAL)) { + onRefresh(); + refresh_timer.start(); + reset_menu_timeout(); + } + BaseScreen::onIdle(); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/feedrate_percent_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/feedrate_percent_screen.cpp new file mode 100644 index 0000000..28f0e6a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/feedrate_percent_screen.cpp @@ -0,0 +1,52 @@ +/******************************* + * feedrate_percent_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; + +void FeedratePercentScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(0).units(GET_TEXT_F(MSG_UNITS_PERCENT)); + + w.heading(GET_TEXT_F(MSG_PRINT_SPEED)); + w.adjuster(4, GET_TEXT_F(MSG_SPEED), getFeedrate_percent()); + w.increments(); +} + +bool FeedratePercentScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 4: UI_DECREMENT(Feedrate_percent); break; + case 5: UI_INCREMENT(Feedrate_percent); break; + default: + return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_menu.cpp new file mode 100644 index 0000000..f63fc41 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_menu.cpp @@ -0,0 +1,85 @@ +/********************* + * filament_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) && ANY(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +#if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_ROWS 9 + #define GRID_COLS 2 + #define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1) + #define RUNOUT_SENSOR_POS BTN_POS(1,2), BTN_SIZE(2,1) + #define LIN_ADVANCE_POS BTN_POS(1,3), BTN_SIZE(2,1) + #define BACK_POS BTN_POS(1,9), BTN_SIZE(2,1) +#else + #define GRID_ROWS 6 + #define GRID_COLS 2 + #define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1) + #define RUNOUT_SENSOR_POS BTN_POS(1,2), BTN_SIZE(2,1) + #define LIN_ADVANCE_POS BTN_POS(1,3), BTN_SIZE(2,1) + #define BACK_POS BTN_POS(1,6), BTN_SIZE(2,1) +#endif + +void FilamentMenu::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) + .text(TITLE_POS, GET_TEXT_F(MSG_FILAMENT)) + .font(font_medium).colors(normal_btn) + .enabled(ENABLED(FILAMENT_RUNOUT_SENSOR)) + .tag(2).button(RUNOUT_SENSOR_POS, GET_TEXT_F(MSG_RUNOUT_SENSOR)) + .enabled(ENABLED(LIN_ADVANCE)) + .tag(3).button(LIN_ADVANCE_POS, GET_TEXT_F(MSG_LINEAR_ADVANCE)) + .colors(action_btn) + .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK)); + } +} + +bool FilamentMenu::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + #if ENABLED(FILAMENT_RUNOUT_SENSOR) + case 2: GOTO_SCREEN(FilamentRunoutScreen); break; + #endif + #if ENABLED(LIN_ADVANCE) + case 3: GOTO_SCREEN(LinearAdvanceScreen); break; + #endif + default: return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp new file mode 100644 index 0000000..41e3be2 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/filament_runout_screen.cpp @@ -0,0 +1,65 @@ +/****************************** + * filament_runout_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, FILAMENT_RUNOUT_SENSOR) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void FilamentRunoutScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.heading( GET_TEXT_F(MSG_FILAMENT)); + w.toggle( 2, GET_TEXT_F(MSG_RUNOUT_SENSOR), getFilamentRunoutEnabled()); + + #if HAS_FILAMENT_RUNOUT_DISTANCE + w.heading(GET_TEXT_F(MSG_RUNOUT_DISTANCE_MM)); + w.units(GET_TEXT_F(MSG_UNITS_MM)); + w.precision(0); + w.color(e_axis); + w.adjuster( 10, progmem_str(NUL_STR), getFilamentRunoutDistance_mm(), getFilamentRunoutEnabled()); + w.increments(); + #endif +} + +bool FilamentRunoutScreen::onTouchHeld(uint8_t tag) { + using namespace ExtUI; + const float increment = getIncrement(); + switch (tag) { + case 2: setFilamentRunoutEnabled(!getFilamentRunoutEnabled()); break; + #if HAS_FILAMENT_RUNOUT_DISTANCE + case 10: UI_DECREMENT(FilamentRunoutDistance_mm); break; + case 11: UI_INCREMENT(FilamentRunoutDistance_mm); break; + #endif + default: + return false; + } + + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp new file mode 100644 index 0000000..cadc582 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/files_screen.cpp @@ -0,0 +1,264 @@ +/******************** + * files_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, SDSUPPORT) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void FilesScreen::onEntry() { + screen_data.Files.cur_page = 0; + screen_data.Files.selected_tag = 0xFF; + #if ENABLED(SCROLL_LONG_FILENAMES) && (FTDI_API_LEVEL >= 810) + CLCD::mem_write_32(CLCD::REG::MACRO_0,DL::NOP); + #endif + gotoPage(0); + BaseScreen::onEntry(); +} + +const char *FilesScreen::getSelectedFilename(bool longName) { + FileList files; + files.seek(getSelectedFileIndex(), true); + return longName ? files.longFilename() : files.shortFilename(); +} + +void FilesScreen::drawSelectedFile() { + FileList files; + files.seek(getSelectedFileIndex(), true); + screen_data.Files.flags.is_dir = files.isDir(); + drawFileButton( + files.filename(), + screen_data.Files.selected_tag, + screen_data.Files.flags.is_dir, + true + ); +} + +uint16_t FilesScreen::getSelectedFileIndex() { + return getFileForTag(screen_data.Files.selected_tag); +} + +uint16_t FilesScreen::getFileForTag(uint8_t tag) { + return screen_data.Files.cur_page * files_per_page + tag - 2; +} + +#if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_COLS 6 + #define GRID_ROWS (files_per_page + header_h + footer_h) +#else + #define GRID_COLS 6 + #define GRID_ROWS (files_per_page + header_h + footer_h) +#endif + +void FilesScreen::drawFileButton(const char* filename, uint8_t tag, bool is_dir, bool is_highlighted) { + const uint8_t line = getLineForTag(tag)+1; + CommandProcessor cmd; + cmd.tag(tag); + cmd.cmd(COLOR_RGB(is_highlighted ? fg_action : bg_color)); + cmd.font(font_medium) + .rectangle( 0, BTN_Y(header_h+line), display_width, BTN_H(1)); + cmd.cmd(COLOR_RGB(is_highlighted ? normal_btn.rgb : bg_text_enabled)); + constexpr uint16_t dim[2] = {BTN_SIZE(6,1)}; + #define POS_AND_SHORTEN(SHORTEN) BTN_POS(1,header_h+line), dim[0] - (SHORTEN), dim[1] + #define POS_AND_SIZE POS_AND_SHORTEN(0) + #if ENABLED(SCROLL_LONG_FILENAMES) + if (is_highlighted) { + cmd.cmd(SAVE_CONTEXT()); + cmd.cmd(MACRO(0)); + cmd.text(POS_AND_SIZE, filename, OPT_CENTERY | OPT_NOFIT); + } else + #endif + draw_text_with_ellipsis(cmd, POS_AND_SHORTEN(is_dir ? 20 : 0), filename, OPT_CENTERY, font_medium); + if (is_dir && !is_highlighted) { + cmd.text(POS_AND_SIZE, F("> "), OPT_CENTERY | OPT_RIGHTX); + } + #if ENABLED(SCROLL_LONG_FILENAMES) + if (is_highlighted) { + cmd.cmd(RESTORE_CONTEXT()); + } + #endif +} + +void FilesScreen::drawFileList() { + FileList files; + screen_data.Files.num_page = max(1,ceil(float(files.count()) / files_per_page)); + screen_data.Files.cur_page = min(screen_data.Files.cur_page, screen_data.Files.num_page-1); + screen_data.Files.flags.is_root = files.isAtRootDir(); + + #undef MARGIN_T + #undef MARGIN_B + #define MARGIN_T 0 + #define MARGIN_B 0 + uint16_t fileIndex = screen_data.Files.cur_page * files_per_page; + for (uint8_t i = 0; i < files_per_page; i++, fileIndex++) { + if (files.seek(fileIndex)) { + drawFileButton(files.filename(), getTagForLine(i), files.isDir(), false); + } + else { + break; + } + } +} + +void FilesScreen::drawHeader() { + const bool prev_enabled = screen_data.Files.cur_page > 0; + const bool next_enabled = screen_data.Files.cur_page < (screen_data.Files.num_page - 1); + + #undef MARGIN_T + #undef MARGIN_B + #define MARGIN_T 0 + #define MARGIN_B 2 + + char str[16]; + sprintf_P(str, PSTR("Page %d of %d"), + screen_data.Files.cur_page + 1, screen_data.Files.num_page); + + CommandProcessor cmd; + cmd.colors(normal_btn) + .font(font_small) + .tag(0).button(BTN_POS(2,1), BTN_SIZE(4,header_h), str, OPT_CENTER | OPT_FLAT) + .font(font_medium) + .colors(action_btn) + .tag(241).enabled(prev_enabled).button(BTN_POS(1,1), BTN_SIZE(1,header_h), F("<")) + .tag(242).enabled(next_enabled).button(BTN_POS(6,1), BTN_SIZE(1,header_h), F(">")); +} + +void FilesScreen::drawFooter() { + #undef MARGIN_T + #undef MARGIN_B + #if ENABLED(TOUCH_UI_PORTRAIT) + #define MARGIN_T 15 + #define MARGIN_B 5 + #else + #define MARGIN_T 5 + #define MARGIN_B 5 + #endif + const bool has_selection = screen_data.Files.selected_tag != 0xFF; + const uint8_t back_tag = screen_data.Files.flags.is_root ? 240 : 245; + const uint8_t y = GRID_ROWS - footer_h + 1; + const uint8_t h = footer_h; + + CommandProcessor cmd; + cmd.colors(normal_btn) + .font(font_medium) + .colors(has_selection ? normal_btn : action_btn) + .tag(back_tag).button(BTN_POS(4,y), BTN_SIZE(3,h), GET_TEXT_F(MSG_BACK)) + .enabled(has_selection) + .colors(has_selection ? action_btn : normal_btn); + + if (screen_data.Files.flags.is_dir) + cmd.tag(244).button(BTN_POS(1, y), BTN_SIZE(3,h), GET_TEXT_F(MSG_BUTTON_OPEN)); + else + cmd.tag(243).button(BTN_POS(1, y), BTN_SIZE(3,h), GET_TEXT_F(MSG_BUTTON_PRINT)); +} + +void FilesScreen::onRedraw(draw_mode_t what) { + if (what & FOREGROUND) { + drawHeader(); + drawSelectedFile(); + drawFooter(); + } +} + +void FilesScreen::gotoPage(uint8_t page) { + screen_data.Files.selected_tag = 0xFF; + screen_data.Files.cur_page = page; + CommandProcessor cmd; + cmd.cmd(CMD_DLSTART) + .cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .colors(normal_btn); + drawFileList(); + storeBackground(); +} + +bool FilesScreen::onTouchEnd(uint8_t tag) { + switch (tag) { + case 240: GOTO_PREVIOUS(); return true; + case 241: + if (screen_data.Files.cur_page > 0) { + gotoPage(screen_data.Files.cur_page-1); + } + break; + case 242: + if (screen_data.Files.cur_page < (screen_data.Files.num_page-1)) { + gotoPage(screen_data.Files.cur_page+1); + } + break; + case 243: + ConfirmStartPrintDialogBox::show(getSelectedFileIndex()); + return true; + case 244: + { + FileList files; + files.changeDir(getSelectedShortFilename()); + gotoPage(0); + } + break; + case 245: + { + FileList files; + files.upDir(); + gotoPage(0); + } + break; + default: + if (tag < 240) { + screen_data.Files.selected_tag = tag; + #if ENABLED(SCROLL_LONG_FILENAMES) && (FTDI_API_LEVEL >= 810) + if (FTDI::ftdi_chip >= 810) { + const char *longFilename = getSelectedLongFilename(); + if (longFilename[0]) { + CommandProcessor cmd; + uint16_t text_width = cmd.font(font_medium).text_width(longFilename); + screen_data.Files.scroll_pos = 0; + if (text_width > display_width) + screen_data.Files.scroll_max = text_width - display_width + MARGIN_L + MARGIN_R; + else + screen_data.Files.scroll_max = 0; + } + } + #endif + } + break; + } + return true; +} + +void FilesScreen::onIdle() { + #if ENABLED(SCROLL_LONG_FILENAMES) && (FTDI_API_LEVEL >= 810) + if (FTDI::ftdi_chip >= 810) { + CLCD::mem_write_32(CLCD::REG::MACRO_0, + VERTEX_TRANSLATE_X(-int32_t(screen_data.Files.scroll_pos))); + if (screen_data.Files.scroll_pos < screen_data.Files.scroll_max * 16) + screen_data.Files.scroll_pos++; + } + #endif +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_settings_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_settings_screen.cpp new file mode 100644 index 0000000..3d50b61 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_settings_screen.cpp @@ -0,0 +1,291 @@ +/********************************* + * interface_settings_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +#include "../archim2-flash/flash_storage.h" + +#include "../../../../../module/settings.h" + +#if ENABLED(LULZBOT_PRINTCOUNTER) + #include "../../../../../module/printcounter.h" +#endif + +bool restoreEEPROM(); + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +constexpr bool PERSISTENT_STORE_SUCCESS = false; // persistentStore uses true for error + +void InterfaceSettingsScreen::onStartup() { +} + +void InterfaceSettingsScreen::onEntry() { + screen_data.InterfaceSettings.brightness = CLCD::get_brightness(); + screen_data.InterfaceSettings.volume = SoundPlayer::get_volume(); + BaseScreen::onEntry(); +} + +void InterfaceSettingsScreen::onRedraw(draw_mode_t what) { + CommandProcessor cmd; + + if (what & BACKGROUND) { + + #define GRID_COLS 4 + #if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_ROWS 7 + #else + #define GRID_ROWS 6 + #endif + + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0) + .font(font_medium) + .text(BTN_POS(1,1), BTN_SIZE(4,1), GET_TEXT_F(MSG_INTERFACE)) + #undef EDGE_R + #define EDGE_R 30 + .font(font_small) + .tag(0) + #if DISABLED(LCD_FYSETC_TFT81050) + .text(BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_LCD_BRIGHTNESS), OPT_RIGHTX | OPT_CENTERY) + #endif + .text(BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_SOUND_VOLUME), OPT_RIGHTX | OPT_CENTERY) + .text(BTN_POS(1,4), BTN_SIZE(2,1), GET_TEXT_F(MSG_SCREEN_LOCK), OPT_RIGHTX | OPT_CENTERY); + #if DISABLED(TOUCH_UI_NO_BOOTSCREEN) + cmd.text(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_BOOT_SCREEN), OPT_RIGHTX | OPT_CENTERY); + #endif + #undef EDGE_R + } + + if (what & FOREGROUND) { + #if ENABLED(TOUCH_UI_PORTRAIT) + constexpr uint8_t w = 2; + #else + constexpr uint8_t w = 1; + #endif + + cmd.font(font_medium) + #define EDGE_R 30 + .colors(ui_slider) + #if DISABLED(LCD_FYSETC_TFT81050) + .tag(2).slider(BTN_POS(3,2), BTN_SIZE(2,1), screen_data.InterfaceSettings.brightness, 128) + #endif + .tag(3).slider(BTN_POS(3,3), BTN_SIZE(2,1), screen_data.InterfaceSettings.volume, 0xFF) + .colors(ui_toggle) + .tag(4).toggle2(BTN_POS(3,4), BTN_SIZE(w,1), GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), LockScreen::is_enabled()) + #if DISABLED(TOUCH_UI_NO_BOOTSCREEN) + .tag(5).toggle2(BTN_POS(3,5), BTN_SIZE(w,1), GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), UIData::animations_enabled()) + #endif + #undef EDGE_R + #define EDGE_R 0 + #if ENABLED(TOUCH_UI_PORTRAIT) + .colors(normal_btn) + .tag(6).button (BTN_POS(1,6), BTN_SIZE(4,1), GET_TEXT_F(MSG_SOUNDS)) + .colors(action_btn) + .tag(1).button (BTN_POS(1,7), BTN_SIZE(4,1), GET_TEXT_F(MSG_BACK)); + #else + .tag(6).button (BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_SOUNDS)) + .colors(action_btn) + .tag(1).button (BTN_POS(3,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_BACK)); + #endif + } +} + +bool InterfaceSettingsScreen::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); return true; + case 4: + if (!LockScreen::is_enabled()) + LockScreen::enable(); + else + LockScreen::disable(); + break; + case 5: UIData::enable_animations(!UIData::animations_enabled());; break; + case 6: GOTO_SCREEN(InterfaceSoundsScreen); return true; + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +bool InterfaceSettingsScreen::onTouchStart(uint8_t tag) { + #undef EDGE_R + #define EDGE_R 30 + CommandProcessor cmd; + switch (tag) { + case 2: cmd.track_linear(BTN_POS(3,3), BTN_SIZE(2,1), 2).execute(); break; + case 3: cmd.track_linear(BTN_POS(3,4), BTN_SIZE(2,1), 3).execute(); break; + default: break; + } + #undef EDGE_R + #define EDGE_R 0 + #undef GRID_COLS + #undef GRID_ROWS + return true; +} + +void InterfaceSettingsScreen::onIdle() { + if (refresh_timer.elapsed(TOUCH_UPDATE_INTERVAL)) { + refresh_timer.start(); + + uint16_t value; + CommandProcessor cmd; + switch (cmd.track_tag(value)) { + case 2: + screen_data.InterfaceSettings.brightness = max(11, (value * 128UL) / 0xFFFF); + CLCD::set_brightness(screen_data.InterfaceSettings.brightness); + SaveSettingsDialogBox::settingsChanged(); + break; + case 3: + screen_data.InterfaceSettings.volume = value >> 8; + SoundPlayer::set_volume(screen_data.InterfaceSettings.volume); + SaveSettingsDialogBox::settingsChanged(); + break; + default: + return; + } + onRefresh(); + } + BaseScreen::onIdle(); +} + +void InterfaceSettingsScreen::failSafeSettings() { + // Reset settings that may make the printer interface + // unusable. + CLCD::mem_write_32(CLCD::REG::ROTATE, 0); + CLCD::default_touch_transform(); + CLCD::default_display_orientation(); + CLCD::set_brightness(255); + UIData::reset_persistent_data(); + CLCD::mem_write_16(CLCD::REG::HOFFSET, FTDI::Hoffset); + CLCD::mem_write_16(CLCD::REG::VOFFSET, FTDI::Voffset); +} + +void InterfaceSettingsScreen::defaultSettings() { + LockScreen::passcode = 0; + SoundPlayer::set_volume(255); + CLCD::set_brightness(255); + UIData::reset_persistent_data(); + InterfaceSoundsScreen::defaultSettings(); + CLCD::mem_write_16(CLCD::REG::HOFFSET, FTDI::Hoffset); + CLCD::mem_write_16(CLCD::REG::VOFFSET, FTDI::Voffset); +} + +void InterfaceSettingsScreen::saveSettings(char *buff) { + static_assert( + ExtUI::eeprom_data_size >= sizeof(persistent_data_t), + "Insufficient space in EEPROM for UI parameters" + ); + + SERIAL_ECHOLNPGM("Writing setting to EEPROM"); + + persistent_data_t eeprom; + + eeprom.passcode = LockScreen::passcode; + eeprom.sound_volume = SoundPlayer::get_volume(); + eeprom.display_brightness = CLCD::get_brightness(); + eeprom.bit_flags = UIData::get_persistent_data(); + eeprom.touch_transform_a = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_A); + eeprom.touch_transform_b = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_B); + eeprom.touch_transform_c = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_C); + eeprom.touch_transform_d = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_D); + eeprom.touch_transform_e = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_E); + eeprom.touch_transform_f = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_F); + eeprom.display_h_offset_adj = CLCD::mem_read_16(CLCD::REG::HOFFSET) - FTDI::Hoffset; + eeprom.display_v_offset_adj = CLCD::mem_read_16(CLCD::REG::VOFFSET) - FTDI::Voffset; + for (uint8_t i = 0; i < InterfaceSoundsScreen::NUM_EVENTS; i++) + eeprom.event_sounds[i] = InterfaceSoundsScreen::event_sounds[i]; + + memcpy(buff, &eeprom, sizeof(eeprom)); +} + +void InterfaceSettingsScreen::loadSettings(const char *buff) { + static_assert( + ExtUI::eeprom_data_size >= sizeof(persistent_data_t), + "Insufficient space in EEPROM for UI parameters" + ); + + persistent_data_t eeprom; + memcpy(&eeprom, buff, sizeof(eeprom)); + + SERIAL_ECHOLNPGM("Loading setting from EEPROM"); + + LockScreen::passcode = eeprom.passcode; + SoundPlayer::set_volume(eeprom.sound_volume); + UIData::set_persistent_data(eeprom.bit_flags); + CLCD::set_brightness(eeprom.display_brightness); + CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_A, eeprom.touch_transform_a); + CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_B, eeprom.touch_transform_b); + CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_C, eeprom.touch_transform_c); + CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_D, eeprom.touch_transform_d); + CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_E, eeprom.touch_transform_e); + CLCD::mem_write_32(CLCD::REG::TOUCH_TRANSFORM_F, eeprom.touch_transform_f); + CLCD::mem_write_16(CLCD::REG::HOFFSET, eeprom.display_h_offset_adj + FTDI::Hoffset); + CLCD::mem_write_16(CLCD::REG::VOFFSET, eeprom.display_v_offset_adj + FTDI::Voffset); + for (uint8_t i = 0; i < InterfaceSoundsScreen::NUM_EVENTS; i++) + InterfaceSoundsScreen::event_sounds[i] = eeprom.event_sounds[i]; + + TERN_(TOUCH_UI_DEVELOPER_MENU, StressTestScreen::startupCheck()); +} + +#ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE + #include "../../../../../HAL/shared/eeprom_api.h" + + bool restoreEEPROM() { + uint8_t data[ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE]; + + bool success = UIFlashStorage::read_config_data(data, ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE); + + if (success) + success = persistentStore.write_data(0, data, ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE) == PERSISTENT_STORE_SUCCESS; + + if (success) + StatusScreen::setStatusMessage(GET_TEXT_F(MSG_EEPROM_RESTORED)); + else + StatusScreen::setStatusMessage(GET_TEXT_F(MSG_EEPROM_RESET)); + + return success; + } + + bool InterfaceSettingsScreen::backupEEPROM() { + uint8_t data[ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE]; + + if (persistentStore.read_data(0, data, ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE) != PERSISTENT_STORE_SUCCESS) + return false; + + UIFlashStorage::write_config_data(data, ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE); + + return true; + } +#endif + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_sounds_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_sounds_screen.cpp new file mode 100644 index 0000000..9f21c6b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/interface_sounds_screen.cpp @@ -0,0 +1,160 @@ +/******************************* + * interface_sounds_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace Theme; +using namespace ExtUI; + +uint8_t InterfaceSoundsScreen::event_sounds[]; + +const char* InterfaceSoundsScreen::getSoundSelection(event_t event) { + return SoundList::name(event_sounds[event]); +} + +void InterfaceSoundsScreen::toggleSoundSelection(event_t event) { + event_sounds[event] = (event_sounds[event]+1) % SoundList::n; + playEventSound(event); +} + +void InterfaceSoundsScreen::setSoundSelection(event_t event, const SoundPlayer::sound_t* sound) { + for (uint8_t i = 0; i < SoundList::n; i++) + if (SoundList::data(i) == sound) + event_sounds[event] = i; +} + +void InterfaceSoundsScreen::playEventSound(event_t event, play_mode_t mode) { + sound.play(SoundList::data(event_sounds[event]), mode); +} + +void InterfaceSoundsScreen::defaultSettings() { + setSoundSelection(PRINTING_STARTED, twinkle); + setSoundSelection(PRINTING_FINISHED, fanfare); + setSoundSelection(PRINTING_FAILED, sad_trombone); +} + +void InterfaceSoundsScreen::onRedraw(draw_mode_t what) { + CommandProcessor cmd; + + if (what & BACKGROUND) { + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0) + + #define GRID_COLS 4 + #define GRID_ROWS 9 + + .font(font_medium) + .text(BTN_POS(1,1), BTN_SIZE(4,1), GET_TEXT_F(MSG_SOUNDS)) + #undef EDGE_R + #define EDGE_R 30 + .font(font_small) + .tag(0).text (BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_SOUND_VOLUME), OPT_RIGHTX | OPT_CENTERY) + .text (BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_CLICK_SOUNDS), OPT_RIGHTX | OPT_CENTERY) + .text (BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_STARTING), OPT_RIGHTX | OPT_CENTERY) + .text (BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_FINISHED), OPT_RIGHTX | OPT_CENTERY) + .text (BTN_POS(1,7), BTN_SIZE(2,1), GET_TEXT_F(MSG_PRINT_ERROR), OPT_RIGHTX | OPT_CENTERY); + #undef EDGE_R + } + + if (what & FOREGROUND) { + #if ENABLED(TOUCH_UI_PORTRAIT) + constexpr uint8_t w = 2; + #else + constexpr uint8_t w = 1; + #endif + + cmd.font(font_medium) + .colors(ui_slider) + #define EDGE_R 30 + .tag(2).slider (BTN_POS(3,2), BTN_SIZE(2,1), screen_data.InterfaceSettings.volume, 0xFF) + .colors(ui_toggle) + .tag(3).toggle2 (BTN_POS(3,3), BTN_SIZE(w,1), GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), UIData::touch_sounds_enabled()) + #undef EDGE_R + .colors(normal_btn) + #define EDGE_R 0 + .tag(4).button (BTN_POS(3,5), BTN_SIZE(2,1), getSoundSelection(PRINTING_STARTED)) + .tag(5).button (BTN_POS(3,6), BTN_SIZE(2,1), getSoundSelection(PRINTING_FINISHED)) + .tag(6).button (BTN_POS(3,7), BTN_SIZE(2,1), getSoundSelection(PRINTING_FAILED)) + .colors(action_btn) + .tag(1).button (BTN_POS(1,9), BTN_SIZE(4,1), GET_TEXT_F(MSG_BACK)); + } +} + +void InterfaceSoundsScreen::onEntry() { + screen_data.InterfaceSettings.volume = SoundPlayer::get_volume(); + BaseScreen::onEntry(); +} + +bool InterfaceSoundsScreen::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); return true; + case 3: UIData::enable_touch_sounds(!UIData::touch_sounds_enabled()); break; + case 4: toggleSoundSelection(PRINTING_STARTED); break; + case 5: toggleSoundSelection(PRINTING_FINISHED); break; + case 6: toggleSoundSelection(PRINTING_FAILED); break; + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +bool InterfaceSoundsScreen::onTouchStart(uint8_t tag) { + CommandProcessor cmd; + #undef EDGE_R + #define EDGE_R 30 + switch (tag) { + case 2: cmd.track_linear(BTN_POS(3,2), BTN_SIZE(2,1), 2).execute(); break; + default: break; + } + return true; +} + +void InterfaceSoundsScreen::onIdle() { + if (refresh_timer.elapsed(TOUCH_UPDATE_INTERVAL)) { + refresh_timer.start(); + + uint16_t value; + CommandProcessor cmd; + switch (cmd.track_tag(value)) { + case 2: + screen_data.InterfaceSettings.volume = value >> 8; + SoundPlayer::set_volume(screen_data.InterfaceSettings.volume); + SaveSettingsDialogBox::settingsChanged(); + break; + default: + return; + } + onRefresh(); + } + BaseScreen::onIdle(); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/jerk_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/jerk_screen.cpp new file mode 100644 index 0000000..9c751bc --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/jerk_screen.cpp @@ -0,0 +1,65 @@ +/******************* + * jerk_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, CLASSIC_JERK) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void JerkScreen::onRedraw(draw_mode_t what) { + + widgets_t w(what); + w.precision(1); + w.units(GET_TEXT_F(MSG_UNITS_MM_S)); + w.heading(GET_TEXT_F(MSG_JERK)); + w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisMaxJerk_mm_s(X) ); + w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_Y), getAxisMaxJerk_mm_s(Y) ); + w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Z), getAxisMaxJerk_mm_s(Z) ); + w.color(e_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_E), getAxisMaxJerk_mm_s(E0) ); + w.increments(); +} + +bool JerkScreen::onTouchHeld(uint8_t tag) { + using namespace ExtUI; + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(AxisMaxJerk_mm_s, X); break; + case 3: UI_INCREMENT(AxisMaxJerk_mm_s, X); break; + case 4: UI_DECREMENT(AxisMaxJerk_mm_s, Y); break; + case 5: UI_INCREMENT(AxisMaxJerk_mm_s, Y); break; + case 6: UI_DECREMENT(AxisMaxJerk_mm_s, Z); break; + case 7: UI_INCREMENT(AxisMaxJerk_mm_s, Z); break; + case 8: UI_DECREMENT(AxisMaxJerk_mm_s, E0); break; + case 9: UI_INCREMENT(AxisMaxJerk_mm_s, E0); break; + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE && CLASSIC_JERK diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/junction_deviation_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/junction_deviation_screen.cpp new file mode 100644 index 0000000..329fa6c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/junction_deviation_screen.cpp @@ -0,0 +1,54 @@ +/******************* + * boot_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, HAS_JUNCTION_DEVIATION) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void JunctionDeviationScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(2); + w.units(GET_TEXT_F(MSG_UNITS_MM)); + w.heading(GET_TEXT_F(MSG_JUNCTION_DEVIATION)); + w.color(other) .adjuster( 2, F(""), getJunctionDeviation_mm() ); + w.increments(); +} + +bool JunctionDeviationScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(JunctionDeviation_mm); break; + case 3: UI_INCREMENT(JunctionDeviation_mm); break; + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE && !CLASSIC_JERK diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/kill_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/kill_screen.cpp new file mode 100644 index 0000000..273da34 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/kill_screen.cpp @@ -0,0 +1,62 @@ +/******************* + * kill_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; + +// The kill screen is an oddball that happens after Marlin has killed the events +// loop. So we only have a show() method rather than onRedraw(). The KillScreen +// should not be used as a model for other UI screens as it is an exception. + +void KillScreen::show(const char *message) { + CommandProcessor cmd; + + cmd.cmd(CMD_DLSTART) + .cmd(CLEAR_COLOR_RGB(Theme::bg_color)) + .cmd(CLEAR(true,true,true)) + .tag(0); + + #define GRID_COLS 4 + #define GRID_ROWS 8 + + cmd.font(Theme::font_large) + .cmd(COLOR_RGB(Theme::bg_text_enabled)) + .text(BTN_POS(1,2), BTN_SIZE(4,1), message) + .text(BTN_POS(1,3), BTN_SIZE(4,1), GET_TEXT_F(MSG_HALTED)) + .text(BTN_POS(1,6), BTN_SIZE(4,1), GET_TEXT_F(MSG_PLEASE_RESET)); + + #undef GRID_COLS + #undef GRID_ROWS + + cmd.cmd(DL::DL_DISPLAY) + .cmd(CMD_SWAP) + .execute(); + + InterfaceSoundsScreen::playEventSound(InterfaceSoundsScreen::PRINTING_FAILED, PLAY_SYNCHRONOUS); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/language_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/language_menu.cpp new file mode 100644 index 0000000..6c5dfcf --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/language_menu.cpp @@ -0,0 +1,66 @@ +/********************* + * language_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" +#include "../language/language.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) && NUM_LANGUAGES > 1 + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +void LanguageMenu::onRedraw(draw_mode_t) { + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color)) + .cmd(CLEAR(true,true,true)) + .colors(normal_btn) + .font(Theme::font_medium); + + #define GRID_ROWS 8 + #define GRID_COLS 1 + + cmd.tag(1).button(BTN_POS(1,1), BTN_SIZE(1,1), GET_LANGUAGE_NAME(1)); + cmd.tag(2).button(BTN_POS(1,2), BTN_SIZE(1,1), GET_LANGUAGE_NAME(2)); + #if NUM_LANGUAGES > 2 + cmd.tag(3).button(BTN_POS(1,3), BTN_SIZE(1,1), GET_LANGUAGE_NAME(3)); + #if NUM_LANGUAGES > 3 + cmd.tag(4).button(BTN_POS(1,4), BTN_SIZE(1,1), GET_LANGUAGE_NAME(4)); + #if NUM_LANGUAGES > 5 + cmd.tag(5).button(BTN_POS(1,5), BTN_SIZE(1,1), GET_LANGUAGE_NAME(5)); + #endif + #endif + #endif +} + +bool LanguageMenu::onTouchEnd(uint8_t tag) { + + if (tag > 0 && tag <= NUM_LANGUAGES) { + lang = tag - 1; + GOTO_SCREEN(StatusScreen); + return true; + } + return false; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/leveling_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/leveling_menu.cpp new file mode 100644 index 0000000..8d37230 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/leveling_menu.cpp @@ -0,0 +1,121 @@ +/********************* + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE,HAS_LEVELING) + +#include "screens.h" + +#if BOTH(HAS_BED_PROBE,BLTOUCH) + #include "../../../../../feature/bltouch.h" +#endif + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +#if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_ROWS 9 + #define GRID_COLS 2 + #define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1) + #define LEVEL_AXIS_POS BTN_POS(1,2), BTN_SIZE(2,1) + #define LEVEL_BED_POS BTN_POS(1,3), BTN_SIZE(2,1) + #define SHOW_MESH_POS BTN_POS(1,4), BTN_SIZE(2,1) + #define BLTOUCH_TITLE_POS BTN_POS(1,6), BTN_SIZE(2,1) + #define BLTOUCH_RESET_POS BTN_POS(1,7), BTN_SIZE(1,1) + #define BLTOUCH_TEST_POS BTN_POS(2,7), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(1,9), BTN_SIZE(2,1) +#else + #define GRID_ROWS 7 + #define GRID_COLS 2 + #define TITLE_POS BTN_POS(1,1), BTN_SIZE(2,1) + #define LEVEL_AXIS_POS BTN_POS(1,2), BTN_SIZE(2,1) + #define LEVEL_BED_POS BTN_POS(1,3), BTN_SIZE(2,1) + #define SHOW_MESH_POS BTN_POS(1,4), BTN_SIZE(2,1) + #define BLTOUCH_TITLE_POS BTN_POS(1,5), BTN_SIZE(2,1) + #define BLTOUCH_RESET_POS BTN_POS(1,6), BTN_SIZE(1,1) + #define BLTOUCH_TEST_POS BTN_POS(2,6), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(1,7), BTN_SIZE(2,1) +#endif + +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(TITLE_POS, GET_TEXT_F(MSG_LEVELING)) + #if ENABLED(BLTOUCH) + .text(BLTOUCH_TITLE_POS, GET_TEXT_F(MSG_BLTOUCH)) + #endif + .font(font_medium).colors(normal_btn) + #if EITHER(Z_STEPPER_AUTO_ALIGN,MECHANICAL_GANTRY_CALIBRATION) + .tag(2).button(LEVEL_AXIS_POS, GET_TEXT_F(MSG_AUTOLEVEL_X_AXIS)) + #endif + .tag(3).button(LEVEL_BED_POS, GET_TEXT_F(MSG_LEVEL_BED)) + .enabled(ENABLED(HAS_MESH)) + .tag(4).button(SHOW_MESH_POS, GET_TEXT_F(MSG_SHOW_MESH)) + #if ENABLED(BLTOUCH) + .tag(5).button(BLTOUCH_RESET_POS, GET_TEXT_F(MSG_BLTOUCH_RESET)) + .tag(6).button(BLTOUCH_TEST_POS, GET_TEXT_F(MSG_BLTOUCH_SELFTEST)) + #endif + .colors(action_btn) + .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK)); + } +} + +bool LevelingMenu::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + #if EITHER(Z_STEPPER_AUTO_ALIGN,MECHANICAL_GANTRY_CALIBRATION) + case 2: SpinnerDialogBox::enqueueAndWait_P(F("G34")); break; + #endif + case 3: + #ifndef BED_LEVELING_COMMANDS + #define BED_LEVELING_COMMANDS "G29" + #endif + #if ENABLED(AUTO_BED_LEVELING_UBL) + BedMeshScreen::startMeshProbe(); + #else + SpinnerDialogBox::enqueueAndWait_P(F(BED_LEVELING_COMMANDS)); + #endif + break; + #if ENABLED(AUTO_BED_LEVELING_UBL) + case 4: GOTO_SCREEN(BedMeshScreen); break; + #endif + #if ENABLED(BLTOUCH) + case 5: injectCommands_P(PSTR("M280 P0 S60")); break; + case 6: SpinnerDialogBox::enqueueAndWait_P(F("M280 P0 S90\nG4 P100\nM280 P0 S120")); break; + #endif + default: return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE && HAS_LEVELING diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/linear_advance_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/linear_advance_screen.cpp new file mode 100644 index 0000000..2feaa03 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/linear_advance_screen.cpp @@ -0,0 +1,77 @@ +/***************************** + * linear_advance_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, LIN_ADVANCE) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void LinearAdvanceScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(2, DEFAULT_LOWEST).color(e_axis); + w.heading( GET_TEXT_F(MSG_LINEAR_ADVANCE)); + #if !HAS_MULTI_EXTRUDER + w.adjuster( 2, GET_TEXT_F(MSG_LINEAR_ADVANCE_K), getLinearAdvance_mm_mm_s(E0) ); + #else + w.adjuster( 2, GET_TEXT_F(MSG_LINEAR_ADVANCE_K1), getLinearAdvance_mm_mm_s(E0) ); + w.adjuster( 4, GET_TEXT_F(MSG_LINEAR_ADVANCE_K2), getLinearAdvance_mm_mm_s(E1) ); + #if EXTRUDERS > 2 + w.adjuster( 6, GET_TEXT_F(MSG_LINEAR_ADVANCE_K3), getLinearAdvance_mm_mm_s(E2) ); + #if EXTRUDERS > 3 + w.adjuster( 8, GET_TEXT_F(MSG_LINEAR_ADVANCE_K4), getLinearAdvance_mm_mm_s(E3) ); + #endif + #endif + #endif + w.increments(); +} + +bool LinearAdvanceScreen::onTouchHeld(uint8_t tag) { + using namespace ExtUI; + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(LinearAdvance_mm_mm_s, E0); break; + case 3: UI_INCREMENT(LinearAdvance_mm_mm_s, E0); break; + #if HAS_MULTI_EXTRUDER + case 4: UI_DECREMENT(LinearAdvance_mm_mm_s, E1); break; + case 5: UI_INCREMENT(LinearAdvance_mm_mm_s, E1); break; + #if EXTRUDERS > 2 + case 6: UI_DECREMENT(LinearAdvance_mm_mm_s, E2); break; + case 7: UI_INCREMENT(LinearAdvance_mm_mm_s, E2); break; + #if EXTRUDERS > 3 + case 8: UI_DECREMENT(LinearAdvance_mm_mm_s, E3); break; + case 9: UI_INCREMENT(LinearAdvance_mm_mm_s, E3); break; + #endif + #endif + #endif + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/lock_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/lock_screen.cpp new file mode 100644 index 0000000..766f414 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/lock_screen.cpp @@ -0,0 +1,205 @@ +/******************* + * lock_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace Theme; + +uint16_t LockScreen::passcode = 0; + +void LockScreen::onEntry() { + const uint8_t siz = sizeof(screen_data.Lock.passcode); + memset(screen_data.Lock.passcode, '_', siz-1); + screen_data.Lock.passcode[siz-1] = '\0'; + BaseScreen::onEntry(); +} + +void LockScreen::onRedraw(draw_mode_t what) { + CommandProcessor cmd; + + if (what & BACKGROUND) { + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0); + } + + if (what & FOREGROUND) { + #if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_COLS 1 + #define GRID_ROWS 10 + #else + #define GRID_COLS 1 + #define GRID_ROWS 7 + #endif + + #undef MARGIN_T + #undef MARGIN_B + #define MARGIN_T 3 + #define MARGIN_B 3 + + progmem_str message; + switch (message_style()) { + case 'w': + message = GET_TEXT_F(MSG_PASSCODE_REJECTED); + break; + case 'g': + message = GET_TEXT_F(MSG_PASSCODE_ACCEPTED); + break; + default: + message = passcode ? GET_TEXT_F(MSG_PASSCODE_REQUEST) : GET_TEXT_F(MSG_PASSCODE_SELECT); + } + message_style() = '\0'; // Terminate the string. + + constexpr uint8_t l = TERN(TOUCH_UI_PORTRAIT, 6, 3); + + const uint8_t pressed = EventLoop::get_pressed_tag(); + + cmd.font(font_large) + #if ENABLED(TOUCH_UI_PORTRAIT) + .text(BTN_POS(1,2), BTN_SIZE(1,1), message) + .font(font_xlarge) + .text(BTN_POS(1,4), BTN_SIZE(1,1), screen_data.Lock.passcode) + #else + .text(BTN_POS(1,1), BTN_SIZE(1,1), message) + .font(font_xlarge) + .text(BTN_POS(1,2), BTN_SIZE(1,1), screen_data.Lock.passcode) + #endif + .font(font_large) + .colors(normal_btn) + #ifdef TOUCH_UI_PASSCODE + .keys(BTN_POS(1,l+1), BTN_SIZE(1,1), F("123"), pressed) + .keys(BTN_POS(1,l+2), BTN_SIZE(1,1), F("456"), pressed) + .keys(BTN_POS(1,l+3), BTN_SIZE(1,1), F("789"), pressed) + .keys(BTN_POS(1,l+4), BTN_SIZE(1,1), F("0.<"), pressed); + #else + .keys(BTN_POS(1,l+1), BTN_SIZE(1,1), F("1234567890"), pressed) + .keys(BTN_POS(1,l+2), BTN_SIZE(1,1), F("qwertyuiop"), pressed) + .keys(BTN_POS(1,l+3), BTN_SIZE(1,1), F("asdfghjkl "), pressed) + .keys(BTN_POS(1,l+4), BTN_SIZE(1,1), F("zxcvbnm!?<"), pressed); + #endif + + #undef MARGIN_T + #undef MARGIN_B + #define MARGIN_T MARGIN_DEFAULT + #define MARGIN_B MARGIN_DEFAULT + + #undef GRID_COLS + #undef GRID_ROWS + } +} + +char &LockScreen::message_style() { + // We use the last byte of the passcode string as a flag to indicate, + // which message to show. + constexpr uint8_t last_char = sizeof(screen_data.Lock.passcode)-1; + return screen_data.Lock.passcode[last_char]; +} + +void LockScreen::onPasscodeEntered() { + if (passcode == 0) { // We are defining a passcode + message_style() = 0; + onRefresh(); + sound.play(twinkle, PLAY_SYNCHRONOUS); + passcode = compute_checksum(); + GOTO_PREVIOUS(); + } + else if (passcode == compute_checksum()) { // We are verifying a passcode + message_style() = 'g'; + onRefresh(); + sound.play(twinkle, PLAY_SYNCHRONOUS); + GOTO_PREVIOUS(); + } + else { + message_style() = 'w'; + onRefresh(); + sound.play(sad_trombone, PLAY_SYNCHRONOUS); + current_screen.forget(); // Discard the screen the user was trying to go to. + GOTO_PREVIOUS(); + } +} + +bool LockScreen::onTouchEnd(uint8_t tag) { + char *c = strchr(screen_data.Lock.passcode,'_'); + if (c) { + if (tag == '<') { + if (c != screen_data.Lock.passcode) { + // Backspace deletes previous entered characters. + *--c = '_'; + } + } + else { + // Append character to passcode + *c++ = tag; + if (*c == '\0') { + // If at last character, then process the code. + onPasscodeEntered(); + } + } + } + return true; +} + +uint16_t LockScreen::compute_checksum() { + uint16_t checksum = 0; + const char* c = screen_data.Lock.passcode; + while (*c) { + checksum = (checksum << 2) ^ *c++; + } + if (checksum == 0) checksum = 0xFFFF; // Prevent a zero checksum + return checksum; +} + +// This function should be called *after* calling GOTO_SCREEN +// to move to new screen. If a passcode is enabled, it will +// immediately jump to the keypad screen, pushing the previous +// screen onto the stack. If the code is entered correctly, +// the stack will be popped, allowing the user to proceed to +// the new screen. Otherwise it will be popped twice, taking +// the user back to where they were before. +void LockScreen::check_passcode() { + if (passcode == 0) return; + message_style() = 0; + GOTO_SCREEN(LockScreen); +} + +bool LockScreen::is_enabled() { + return passcode != 0; +} + +void LockScreen::disable() { + passcode = 0; +} + +void LockScreen::enable() { + message_style() = 0; + passcode = 0; + GOTO_SCREEN(LockScreen); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/main_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/main_menu.cpp new file mode 100644 index 0000000..146b799 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/main_menu.cpp @@ -0,0 +1,131 @@ +/***************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) && NONE(TOUCH_UI_LULZBOT_BIO,TOUCH_UI_COCOA_PRESS) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +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 ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_ROWS 8 + #define GRID_COLS 2 + #define ABOUT_PRINTER_POS BTN_POS(1,1), BTN_SIZE(2,1) + #define ADVANCED_SETTINGS_POS BTN_POS(1,2), BTN_SIZE(2,1) + #if ENABLED(CUSTOM_USER_MENUS) + #define FILAMENTCHANGE_POS BTN_POS(1,3), BTN_SIZE(1,1) + #define CUSTOM_USER_MENUS_POS BTN_POS(2,3), BTN_SIZE(1,1) + #else + #define FILAMENTCHANGE_POS BTN_POS(1,3), BTN_SIZE(2,1) + #endif + #define TEMPERATURE_POS BTN_POS(1,4), BTN_SIZE(2,1) + #define DISABLE_STEPPERS_POS BTN_POS(1,5), BTN_SIZE(2,1) + #define MOVE_AXIS_POS BTN_POS(1,6), BTN_SIZE(1,1) + #define LEVELING_POS BTN_POS(2,6), BTN_SIZE(1,1) + #define AUTO_HOME_POS BTN_POS(1,7), BTN_SIZE(1,1) + #define CLEAN_NOZZLE_POS BTN_POS(2,7), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(1,8), BTN_SIZE(2,1) + #else + #define GRID_ROWS 5 + #define GRID_COLS 6 + #define ADVANCED_SETTINGS_POS BTN_POS(1,1), BTN_SIZE(3,1) + #define ABOUT_PRINTER_POS BTN_POS(4,1), BTN_SIZE(3,1) + #define AUTO_HOME_POS BTN_POS(1,2), BTN_SIZE(3,1) + #define CLEAN_NOZZLE_POS BTN_POS(4,2), BTN_SIZE(3,1) + #define MOVE_AXIS_POS BTN_POS(1,3), BTN_SIZE(3,1) + #define DISABLE_STEPPERS_POS BTN_POS(4,3), BTN_SIZE(3,1) + #if ENABLED(CUSTOM_USER_MENUS) + #define TEMPERATURE_POS BTN_POS(1,4), BTN_SIZE(2,1) + #define FILAMENTCHANGE_POS BTN_POS(3,4), BTN_SIZE(2,1) + #define CUSTOM_USER_MENUS_POS BTN_POS(5,4), BTN_SIZE(2,1) + #else + #define TEMPERATURE_POS BTN_POS(1,4), BTN_SIZE(3,1) + #define FILAMENTCHANGE_POS BTN_POS(4,4), BTN_SIZE(3,1) + #endif + #define LEVELING_POS BTN_POS(1,5), BTN_SIZE(3,1) + #define BACK_POS BTN_POS(4,5), BTN_SIZE(3,1) + #endif + + if (what & FOREGROUND) { + CommandProcessor cmd; + cmd.colors(normal_btn) + .font(Theme::font_medium) + .tag( 2).button(AUTO_HOME_POS, GET_TEXT_F(MSG_AUTO_HOME)) + .enabled(ENABLED(NOZZLE_CLEAN_FEATURE)) + .tag( 3).button(CLEAN_NOZZLE_POS, GET_TEXT_F(MSG_CLEAN_NOZZLE)) + .tag( 4).button(MOVE_AXIS_POS, GET_TEXT_F(MSG_MOVE_AXIS)) + .tag( 5).button(DISABLE_STEPPERS_POS,GET_TEXT_F(MSG_DISABLE_STEPPERS)) + .tag( 6).button(TEMPERATURE_POS, GET_TEXT_F(MSG_TEMPERATURE)) + .enabled(IF_DISABLED(TOUCH_UI_LULZBOT_BIO, 1)) + .tag( 7).button(FILAMENTCHANGE_POS, GET_TEXT_F(MSG_FILAMENTCHANGE)) + .tag( 8).button(ADVANCED_SETTINGS_POS, GET_TEXT_F(MSG_ADVANCED_SETTINGS)) + .enabled(TERN_(HAS_LEVELING, 1)) + .tag( 9).button(LEVELING_POS, GET_TEXT_F(MSG_LEVELING)) + .tag(10).button(ABOUT_PRINTER_POS, GET_TEXT_F(MSG_INFO_MENU)) + #if ENABLED(CUSTOM_USER_MENUS) + .tag(11).button(CUSTOM_USER_MENUS_POS, GET_TEXT_F(MSG_USER_MENU)) + #endif + .colors(action_btn) + .tag(1).button(BACK_POS, GET_TEXT_F(MSG_BACK)); + } +} + +bool MainMenu::onTouchEnd(uint8_t tag) { + using namespace ExtUI; + + switch (tag) { + case 1: SaveSettingsDialogBox::promptToSaveSettings(); break; + case 2: SpinnerDialogBox::enqueueAndWait_P(F("G28")); break; + #if ENABLED(NOZZLE_CLEAN_FEATURE) + case 3: injectCommands_P(PSTR("G12")); GOTO_SCREEN(StatusScreen); break; + #endif + case 4: GOTO_SCREEN(MoveAxisScreen); break; + case 5: injectCommands_P(PSTR("M84")); break; + case 6: GOTO_SCREEN(TemperatureScreen); break; + case 7: GOTO_SCREEN(ChangeFilamentScreen); break; + case 8: GOTO_SCREEN(AdvancedSettingsMenu); break; + #if HAS_LEVELING + case 9: GOTO_SCREEN(LevelingMenu); break; + #endif + case 10: GOTO_SCREEN(AboutScreen); break; + #if ENABLED(CUSTOM_USER_MENUS) + case 11: GOTO_SCREEN(CustomUserMenus); break; + #endif + + default: + return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE && !TOUCH_UI_LULZBOT_BIO diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_acceleration_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_acceleration_screen.cpp new file mode 100644 index 0000000..fdbb962 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_acceleration_screen.cpp @@ -0,0 +1,86 @@ +/******************************* + * max_acceleration_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void MaxAccelerationScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(0); + w.units(GET_TEXT_F(MSG_UNITS_MM_S2)); + w.heading(GET_TEXT_F(MSG_ACCELERATION)); + w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AMAX_X), getAxisMaxAcceleration_mm_s2(X) ); + w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_AMAX_Y), getAxisMaxAcceleration_mm_s2(Y) ); + w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_AMAX_Z), getAxisMaxAcceleration_mm_s2(Z) ); + #if DISTINCT_E == 1 + w.color(e_axis).adjuster( 8, GET_TEXT_F(MSG_AMAX_E), getAxisMaxAcceleration_mm_s2(E0) ); + #elif DISTINCT_E > 1 + w.heading(GET_TEXT_F(MSG_AMAX_E)); + w.color(e_axis).adjuster( 8, F(LCD_STR_E0), getAxisMaxAcceleration_mm_s2(E0) ); + w.color(e_axis).adjuster(10, F(LCD_STR_E1), getAxisMaxAcceleration_mm_s2(E1) ); + #if DISTINCT_E > 2 + w.color(e_axis).adjuster(12, F(LCD_STR_E2), getAxisMaxAcceleration_mm_s2(E2) ); + #endif + #if DISTINCT_E > 3 + w.color(e_axis).adjuster(14, F(LCD_STR_E3), getAxisMaxAcceleration_mm_s2(E3) ); + #endif + #endif + w.increments(); +} + +bool MaxAccelerationScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(AxisMaxAcceleration_mm_s2, X ); break; + case 3: UI_INCREMENT(AxisMaxAcceleration_mm_s2, X ); break; + case 4: UI_DECREMENT(AxisMaxAcceleration_mm_s2, Y ); break; + case 5: UI_INCREMENT(AxisMaxAcceleration_mm_s2, Y ); break; + case 6: UI_DECREMENT(AxisMaxAcceleration_mm_s2, Z ); break; + case 7: UI_INCREMENT(AxisMaxAcceleration_mm_s2, Z ); break; + case 8: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E0); break; + case 9: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E0); break; + #if DISTINCT_E > 1 + case 10: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E1); break; + case 11: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E1); break; + #endif + #if DISTINCT_E > 2 + case 12: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E2); break; + case 13: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E2); break; + #endif + #if DISTINCT_E > 3 + case 14: UI_DECREMENT(AxisMaxAcceleration_mm_s2, E3); break; + case 15: UI_INCREMENT(AxisMaxAcceleration_mm_s2, E3); break; + #endif + default: + return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_velocity_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_velocity_screen.cpp new file mode 100644 index 0000000..ac1374b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/max_velocity_screen.cpp @@ -0,0 +1,90 @@ +/*************************** + * max_velocity_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void MaxVelocityScreen::onRedraw(draw_mode_t what) { + using namespace ExtUI; + widgets_t w(what); + w.precision(0); + w.units(GET_TEXT_F(MSG_UNITS_MM_S)); + w.heading( GET_TEXT_F(MSG_VELOCITY)); + w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_VMAX_X), getAxisMaxFeedrate_mm_s(X) ); + w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_VMAX_Y), getAxisMaxFeedrate_mm_s(Y) ); + w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_VMAX_Z), getAxisMaxFeedrate_mm_s(Z) ); + #if EXTRUDERS == 1 || DISABLED(DISTINCT_E_FACTORS) + w.color(e_axis) .adjuster( 8, GET_TEXT_F(MSG_VMAX_E), getAxisMaxFeedrate_mm_s(E0) ); + #elif HAS_MULTI_EXTRUDER + w.heading(GET_TEXT_F(MSG_VMAX_E)); + w.color(e_axis) .adjuster( 8, F(LCD_STR_E0), getAxisMaxFeedrate_mm_s(E0) ); + w.color(e_axis) .adjuster( 10, F(LCD_STR_E1), getAxisMaxFeedrate_mm_s(E1) ); + #if EXTRUDERS > 2 + w.color(e_axis).adjuster( 12, F(LCD_STR_E2), getAxisMaxFeedrate_mm_s(E2) ); + #endif + #if EXTRUDERS > 3 + w.color(e_axis).adjuster( 14, F(LCD_STR_E3), getAxisMaxFeedrate_mm_s(E3) ); + #endif + #endif + w.increments(); +} + +bool MaxVelocityScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(AxisMaxFeedrate_mm_s, X); break; + case 3: UI_INCREMENT(AxisMaxFeedrate_mm_s, X); break; + case 4: UI_DECREMENT(AxisMaxFeedrate_mm_s, Y); break; + case 5: UI_INCREMENT(AxisMaxFeedrate_mm_s, Y); break; + case 6: UI_DECREMENT(AxisMaxFeedrate_mm_s, Z); break; + case 7: UI_INCREMENT(AxisMaxFeedrate_mm_s, Z); break; + #if DISTINCT_E > 0 + case 8: UI_DECREMENT(AxisMaxFeedrate_mm_s, E0); break; + case 9: UI_INCREMENT(AxisMaxFeedrate_mm_s, E0); break; + #endif + #if DISTINCT_E > 1 + case 10: UI_DECREMENT(AxisMaxFeedrate_mm_s, E1); break; + case 11: UI_INCREMENT(AxisMaxFeedrate_mm_s, E1); break; + #endif + #if DISTINCT_E > 2 + case 12: UI_DECREMENT(AxisMaxFeedrate_mm_s, E2); break; + case 13: UI_INCREMENT(AxisMaxFeedrate_mm_s, E2); break; + #endif + #if DISTINCT_E > 3 + case 14: UI_DECREMENT(AxisMaxFeedrate_mm_s, E3); break; + case 15: UI_INCREMENT(AxisMaxFeedrate_mm_s, E3); break; + #endif + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/media_player_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/media_player_screen.cpp new file mode 100644 index 0000000..eb0b78a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/media_player_screen.cpp @@ -0,0 +1,168 @@ +/*************************** + * media_player_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +/** + * The MediaPlayerScreen allows an AVI to be played. + * + * It requires a special AVI file. The following video + * and audio codecs must be used: + * + * -vcodec mjpeg -pix_fmt yuvj420p + * -acodec adpcm_ima_wav + * + * To generate a 2 second static screen from a png file: + * + * ffmpeg -i startup.png -vcodec mjpeg -pix_fmt yuvj420p -r 1 video.avi + * sox -n -r 44100 -b 8 -c 2 -L silence.wav trim 0.0 2.000 + * ffmpeg -i silence.wav -acodec adpcm_ima_wav silence.avi + * ffmpeg -i video.avi -i silence.wav -c copy -map 0:v:0 -map 1:a:0 startup.avi + */ + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +#include "../archim2-flash/flash_storage.h" +#include "../archim2-flash/media_file_reader.h" + +using namespace FTDI; + +void MediaPlayerScreen::onEntry() { + BaseScreen::onEntry(); + CLCD::turn_on_backlight(); + SoundPlayer::set_volume(255); +} + +void MediaPlayerScreen::onRedraw(draw_mode_t) { +} + +bool MediaPlayerScreen::playCardMedia() { + #if ENABLED(SDSUPPORT) + char fname[15]; + strcpy_P(fname, PSTR("STARTUP.AVI")); + + MediaFileReader reader; + if (!reader.open(fname)) + return false; + + SERIAL_ECHO_MSG("Starting to play STARTUP.AVI"); + playStream(&reader, MediaFileReader::read); + reader.close(); + #endif + return true; +} + +// Attempt to play media from the onboard SPI flash chip +bool MediaPlayerScreen::playBootMedia() { + UIFlashStorage::BootMediaReader reader; + if (!reader.isAvailable()) return false; + + SERIAL_ECHO_MSG("Starting to play boot video"); + playStream(&reader, UIFlashStorage::BootMediaReader::read); + return true; +} + +void MediaPlayerScreen::playStream(void *obj, media_streamer_func_t *data_stream) { + #if FTDI_API_LEVEL >= 810 + if (FTDI::ftdi_chip >= 810) { + // Set up the media FIFO on the end of RAMG, as the top of RAMG + // will be used as the framebuffer. + + uint8_t buf[512]; + const uint32_t block_size = 512; + const uint32_t fifo_size = block_size * 2; + const uint32_t fifo_start = CLCD::MAP::RAM_G + CLCD::MAP::RAM_G_SIZE - fifo_size; + + CommandProcessor cmd; + cmd.cmd(CMD_DLSTART) + .cmd(CLEAR_COLOR_RGB(0x000000)) + .cmd(CLEAR(true,true,true)) + .cmd(DL::DL_DISPLAY) + .cmd(CMD_SWAP) + .execute() + .cmd(CMD_DLSTART) + .mediafifo(fifo_start, fifo_size) + .playvideo(OPT_FULLSCREEN | OPT_MEDIAFIFO | OPT_NOTEAR | OPT_SOUND) + .cmd(DL::DL_DISPLAY) + .cmd(CMD_SWAP) + .execute(); + + uint32_t writePtr = 0; + int16_t nBytes; + + uint32_t t = millis(); + uint8_t timeouts; + + spiInit(SPI_HALF_SPEED); // Boost SPI speed for video playback + + do { + // Write block n + nBytes = (*data_stream)(obj, buf, block_size); + if (nBytes == -1) break; + + if (millis() - t > 10) { + ExtUI::yield(); + t = millis(); + } + + CLCD::mem_write_bulk (fifo_start + writePtr, buf, nBytes); + + // Wait for FTDI810 to finish playing block n-1 + timeouts = 20; + do { + if (millis() - t > 10) { + ExtUI::yield(); + t = millis(); + timeouts--; + if (timeouts == 0) { + SERIAL_ECHO_MSG("Timeout playing video"); + cmd.reset(); + goto exit; + } + } + } while (CLCD::mem_read_32(CLCD::REG::MEDIAFIFO_READ) != writePtr); + + // Start playing block n + writePtr = (writePtr + nBytes) % fifo_size; + CLCD::mem_write_32(CLCD::REG::MEDIAFIFO_WRITE, writePtr); + } while (nBytes == block_size); + + SERIAL_ECHO_MSG("Done playing video"); + + exit: + spiInit(SD_SPI_SPEED); // Restore default speed + + // Since playing media overwrites RAMG, we need to reinitialize + // everything that is stored in RAMG. + cmd.cmd(CMD_DLSTART).execute(); + DLCache::init(); + StatusScreen::loadBitmaps(); + } + #else + UNUSED(obj); + UNUSED(data_stream); + #endif // FTDI_API_LEVEL >= 810 +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/move_axis_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/move_axis_screen.cpp new file mode 100644 index 0000000..ba38918 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/move_axis_screen.cpp @@ -0,0 +1,133 @@ +/************************ + * move_axis_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace ExtUI; + +void BaseMoveAxisScreen::onEntry() { + // Since Marlin keeps only one absolute position for all the extruders, + // we have to keep track of the relative motion of individual extruders + // ourselves. The relative distances are reset to zero whenever this + // screen is entered. + + LOOP_L_N(i, ExtUI::extruderCount) { + screen_data.MoveAxis.e_rel[i] = 0; + } + BaseNumericAdjustmentScreen::onEntry(); +} + +void MoveAxisScreen::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_MOVE_AXIS)); + 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.color(Theme::e_axis); + #if EXTRUDERS == 1 + w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E), screen_data.MoveAxis.e_rel[0], canMove(E0)); + #elif HAS_MULTI_EXTRUDER + w.adjuster( 8, GET_TEXT_F(MSG_AXIS_E1), screen_data.MoveAxis.e_rel[0], canMove(E0)); + w.adjuster( 10, GET_TEXT_F(MSG_AXIS_E2), screen_data.MoveAxis.e_rel[1], canMove(E1)); + #if EXTRUDERS > 2 + w.adjuster( 12, GET_TEXT_F(MSG_AXIS_E3), screen_data.MoveAxis.e_rel[2], canMove(E2)); + #endif + #if EXTRUDERS > 3 + w.adjuster( 14, GET_TEXT_F(MSG_AXIS_E4), screen_data.MoveAxis.e_rel[3], canMove(E3)); + #endif + #endif + w.increments(); +} + +bool BaseMoveAxisScreen::onTouchHeld(uint8_t tag) { + #define UI_INCREMENT_AXIS(axis) UI_INCREMENT(AxisPosition_mm, axis); + #define UI_DECREMENT_AXIS(axis) UI_DECREMENT(AxisPosition_mm, axis); + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT_AXIS(X); break; + case 3: UI_INCREMENT_AXIS(X); break; + case 4: UI_DECREMENT_AXIS(Y); break; + case 5: UI_INCREMENT_AXIS(Y); break; + case 6: UI_DECREMENT_AXIS(Z); break; + case 7: UI_INCREMENT_AXIS(Z); break; + // For extruders, also update relative distances. + case 8: UI_DECREMENT_AXIS(E0); screen_data.MoveAxis.e_rel[0] -= increment; break; + case 9: UI_INCREMENT_AXIS(E0); screen_data.MoveAxis.e_rel[0] += increment; break; + #if HAS_MULTI_EXTRUDER + case 10: UI_DECREMENT_AXIS(E1); screen_data.MoveAxis.e_rel[1] -= increment; break; + case 11: UI_INCREMENT_AXIS(E1); screen_data.MoveAxis.e_rel[1] += increment; break; + #endif + #if EXTRUDERS > 2 + case 12: UI_DECREMENT_AXIS(E2); screen_data.MoveAxis.e_rel[2] -= increment; break; + case 13: UI_INCREMENT_AXIS(E2); screen_data.MoveAxis.e_rel[2] += increment; break; + #endif + #if EXTRUDERS > 3 + case 14: UI_DECREMENT_AXIS(E3); screen_data.MoveAxis.e_rel[3] -= increment; break; + case 15: UI_INCREMENT_AXIS(E3); screen_data.MoveAxis.e_rel[3] += increment; break; + #endif + case 20: SpinnerDialogBox::enqueueAndWait_P(F("G28X")); break; + case 21: SpinnerDialogBox::enqueueAndWait_P(F("G28Y")); break; + case 22: SpinnerDialogBox::enqueueAndWait_P(F("G28Z")); break; + case 23: SpinnerDialogBox::enqueueAndWait_P(F("G28")); break; + default: + return false; + } + #undef UI_DECREMENT_AXIS + #undef UI_INCREMENT_AXIS + return true; +} + +float BaseMoveAxisScreen::getManualFeedrate(uint8_t axis, float increment_mm) { + // Compute 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. + constexpr xyze_feedrate_t max_manual_feedrate = MANUAL_FEEDRATE; + return min(max_manual_feedrate[axis] / 60.0f, abs(increment_mm * (TOUCH_REPEATS_PER_SECOND) * 0.80f)); +} + +void BaseMoveAxisScreen::setManualFeedrate(ExtUI::axis_t axis, float increment_mm) { + ExtUI::setFeedrate_mm_s(getManualFeedrate(X_AXIS + (axis - ExtUI::X), increment_mm)); +} + +void BaseMoveAxisScreen::setManualFeedrate(ExtUI::extruder_t, float increment_mm) { + ExtUI::setFeedrate_mm_s(getManualFeedrate(E_AXIS, increment_mm)); +} + +void MoveAxisScreen::onIdle() { + if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) { + onRefresh(); + refresh_timer.start(); + } + BaseScreen::onIdle(); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nozzle_offsets_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nozzle_offsets_screen.cpp new file mode 100644 index 0000000..85c7206 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nozzle_offsets_screen.cpp @@ -0,0 +1,73 @@ +/***************************** + * nozzle_offsets_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, HAS_MULTI_HOTEND) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; + +void NozzleOffsetScreen::onEntry() { + // Since we don't allow the user to edit the offsets for E0, + // make sure they are all zero. + normalizeNozzleOffset(X); + normalizeNozzleOffset(Y); + normalizeNozzleOffset(Z); +} + +void NozzleOffsetScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(2).units(GET_TEXT_F(MSG_UNITS_MM)); + + w.heading( GET_TEXT_F(MSG_OFFSETS_MENU)); + w.color(Theme::x_axis).adjuster(2, GET_TEXT_F(MSG_AXIS_X), ExtUI::getNozzleOffset_mm(X, E1)); + w.color(Theme::y_axis).adjuster(4, GET_TEXT_F(MSG_AXIS_Y), ExtUI::getNozzleOffset_mm(Y, E1)); + w.color(Theme::z_axis).adjuster(6, GET_TEXT_F(MSG_AXIS_Z), ExtUI::getNozzleOffset_mm(Z, E1)); + #if ENABLED(CALIBRATION_GCODE) + w.button(8, GET_TEXT_F(MSG_MEASURE_AUTOMATICALLY), !isPrinting()); + #endif + w.increments(); +} + +bool NozzleOffsetScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(NozzleOffset_mm, X, E1); break; + case 3: UI_INCREMENT(NozzleOffset_mm, X, E1); break; + case 4: UI_DECREMENT(NozzleOffset_mm, Y, E1); break; + case 5: UI_INCREMENT(NozzleOffset_mm, Y, E1); break; + case 6: UI_DECREMENT(NozzleOffset_mm, Z, E1); break; + case 7: UI_INCREMENT(NozzleOffset_mm, Z, E1); break; + #if ENABLED(CALIBRATION_GCODE) + case 8: GOTO_SCREEN(ConfirmAutoCalibrationDialogBox); return true; + #endif + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nudge_nozzle_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nudge_nozzle_screen.cpp new file mode 100644 index 0000000..f0d3f7e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/nudge_nozzle_screen.cpp @@ -0,0 +1,123 @@ +/******************** + * nudge_nozzle.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, BABYSTEPPING) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace Theme; +using namespace ExtUI; + +void NudgeNozzleScreen::onEntry() { + screen_data.NudgeNozzle.show_offsets = false; + #if HAS_MULTI_EXTRUDER + screen_data.NudgeNozzle.link_nozzles = true; + #endif + screen_data.NudgeNozzle.rel.reset(); + + BaseNumericAdjustmentScreen::onEntry(); +} + +void NudgeNozzleScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(2, BaseNumericAdjustmentScreen::DEFAULT_MIDRANGE).units(GET_TEXT_F(MSG_UNITS_MM)); + + w.heading(GET_TEXT_F(MSG_NUDGE_NOZZLE)); + #if ENABLED(BABYSTEP_XY) + w.color(x_axis).adjuster(2, GET_TEXT_F(MSG_AXIS_X), screen_data.NudgeNozzle.rel.x / getAxisSteps_per_mm(X)); + w.color(y_axis).adjuster(4, GET_TEXT_F(MSG_AXIS_Y), screen_data.NudgeNozzle.rel.y / getAxisSteps_per_mm(Y)); + #endif + w.color(z_axis).adjuster(6, GET_TEXT_F(MSG_AXIS_Z), screen_data.NudgeNozzle.rel.z / getAxisSteps_per_mm(Z)); + w.increments(); + #if HAS_MULTI_EXTRUDER + w.toggle(8, GET_TEXT_F(MSG_ADJUST_BOTH_NOZZLES), screen_data.NudgeNozzle.link_nozzles); + #endif + + #if HAS_MULTI_EXTRUDER || HAS_BED_PROBE + w.toggle(9, GET_TEXT_F(MSG_SHOW_OFFSETS), screen_data.NudgeNozzle.show_offsets); + + if (screen_data.NudgeNozzle.show_offsets) { + char str[19]; + + w.draw_mode(BOTH); + w.color(other); + + #if HAS_BED_PROBE + dtostrf(getZOffset_mm(), 4, 2, str); + strcat(str, " "); + strcat_P(str, GET_TEXT(MSG_UNITS_MM)); + w.text_field(0, GET_TEXT_F(MSG_ZPROBE_ZOFFSET), str); + #endif + + #if HAS_MULTI_HOTEND + format_position(str, getNozzleOffset_mm(X, E1), getNozzleOffset_mm(Y, E1), getNozzleOffset_mm(Z, E1)); + w.text_field(0, GET_TEXT_F(MSG_OFFSETS_MENU), str); + #endif + } + #endif +} + +bool NudgeNozzleScreen::onTouchHeld(uint8_t tag) { + const float inc = getIncrement(); + #if HAS_MULTI_EXTRUDER + const bool link = screen_data.NudgeNozzle.link_nozzles; + #else + constexpr bool link = true; + #endif + int16_t steps; + switch (tag) { + case 2: steps = mmToWholeSteps(inc, X); smartAdjustAxis_steps(-steps, X, link); screen_data.NudgeNozzle.rel.x -= steps; break; + case 3: steps = mmToWholeSteps(inc, X); smartAdjustAxis_steps( steps, X, link); screen_data.NudgeNozzle.rel.x += steps; break; + case 4: steps = mmToWholeSteps(inc, Y); smartAdjustAxis_steps(-steps, Y, link); screen_data.NudgeNozzle.rel.y -= steps; break; + case 5: steps = mmToWholeSteps(inc, Y); smartAdjustAxis_steps( steps, Y, link); screen_data.NudgeNozzle.rel.y += steps; break; + case 6: steps = mmToWholeSteps(inc, Z); smartAdjustAxis_steps(-steps, Z, link); screen_data.NudgeNozzle.rel.z -= steps; break; + case 7: steps = mmToWholeSteps(inc, Z); smartAdjustAxis_steps( steps, Z, link); screen_data.NudgeNozzle.rel.z += steps; break; + #if HAS_MULTI_EXTRUDER + case 8: screen_data.NudgeNozzle.link_nozzles = !link; break; + #endif + case 9: screen_data.NudgeNozzle.show_offsets = !screen_data.NudgeNozzle.show_offsets; break; + default: return false; + } + #if HAS_MULTI_EXTRUDER || HAS_BED_PROBE + SaveSettingsDialogBox::settingsChanged(); + #endif + return true; +} + +bool NudgeNozzleScreen::onTouchEnd(uint8_t tag) { + if (tag == 1) { + SaveSettingsDialogBox::promptToSaveSettings(); + return true; + } + else + return BaseNumericAdjustmentScreen::onTouchEnd(tag); +} + +void NudgeNozzleScreen::onIdle() { + reset_menu_timeout(); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/restore_failsafe_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/restore_failsafe_dialog_box.cpp new file mode 100644 index 0000000..9be2239 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/restore_failsafe_dialog_box.cpp @@ -0,0 +1,51 @@ +/*********************************** + * restore_failsafe_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace ExtUI; + +void RestoreFailsafeDialogBox::onRedraw(draw_mode_t) { + drawMessage(GET_TEXT_F(MSG_EEPROM_RESET_WARNING)); + drawYesNoButtons(); +} + +bool RestoreFailsafeDialogBox::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: + ExtUI::injectCommands_P(PSTR("M502")); + AlertDialogBox::show(GET_TEXT_F(MSG_EEPROM_RESET)); + // Remove RestoreFailsafeDialogBox from the stack + // so the alert box doesn't return to it. + current_screen.forget(); + SaveSettingsDialogBox::settingsChanged(); + return true; + default: + return DialogBoxBaseClass::onTouchEnd(tag); + } +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/save_settings_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/save_settings_dialog_box.cpp new file mode 100644 index 0000000..eff0431 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/save_settings_dialog_box.cpp @@ -0,0 +1,64 @@ +/******************************** + * save_settings_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace ExtUI; + +bool SaveSettingsDialogBox::needs_save = false; + +void SaveSettingsDialogBox::onRedraw(draw_mode_t) { + drawMessage(GET_TEXT_F(MSG_EEPROM_SAVE_PROMPT)); + drawYesNoButtons(); +} + +bool SaveSettingsDialogBox::onTouchEnd(uint8_t tag) { + needs_save = false; + switch (tag) { + case 1: + injectCommands_P(PSTR("M500")); + AlertDialogBox::show(GET_TEXT_F(MSG_EEPROM_SAVED)); + // Remove SaveSettingsDialogBox from the stack + // so the alert box doesn't return to me. + current_screen.forget(); + return true; + default: + return DialogBoxBaseClass::onTouchEnd(tag); + } +} + +void SaveSettingsDialogBox::promptToSaveSettings() { + if (needs_save) { + // Remove current screen from the stack + // so SaveSettingsDialogBox doesn't return here. + GOTO_SCREEN(SaveSettingsDialogBox); + current_screen.forget(); + } + else + GOTO_PREVIOUS(); // No save needed. +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screen_data.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screen_data.h new file mode 100644 index 0000000..fe35fc4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screen_data.h @@ -0,0 +1,97 @@ +/***************** + * screen_data.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +#include "../ftdi_eve_lib/ftdi_eve_lib.h" + +// To save RAM, store state information related to a particular screen +// in a union. The values should be initialized in the onEntry method. + +struct base_numeric_adjustment_t {uint8_t increment;}; + +union screen_data_t { + struct base_numeric_adjustment_t BaseNumericAdjustment; + struct {uint8_t volume; uint8_t brightness;} InterfaceSettings; + struct {char passcode[5];} Lock; + struct {bool isError;} AlertDialog; + struct {bool auto_hide;} SpinnerDialog; + struct {uint8_t file_index;} ConfirmStartPrintDialog; + struct { + uint8_t e_tag, t_tag, repeat_tag; + ExtUI::extruder_t saved_extruder; + #if FILAMENT_UNLOAD_PURGE_LENGTH > 0 + bool need_purge; + #endif + } ChangeFilament; + struct { + struct { + uint8_t is_dir : 1; + uint8_t is_root : 1; + } flags; + uint8_t selected_tag; + uint8_t num_page; + uint8_t cur_page; + #if ENABLED(SCROLL_LONG_FILENAMES) && (FTDI_API_LEVEL >= 810) + uint16_t scroll_pos; + uint16_t scroll_max; + #endif + } Files; + struct { + struct base_numeric_adjustment_t placeholder; + float e_rel[ExtUI::extruderCount]; + } MoveAxis; + #if HAS_MESH + struct { + enum : uint8_t { + MSG_NONE, + MSG_MESH_COMPLETE, + MSG_MESH_INCOMPLETE + } message; + uint8_t count; + uint8_t highlightedTag; + } BedMesh; + #endif + #if ENABLED(TOUCH_UI_DEVELOPER_MENU) + struct { + uint32_t next_watchdog_trigger; + const char* message; + } StressTest; + #endif + #if ENABLED(TOUCH_UI_COCOA_PRESS) + struct { + uint32_t start_ms; + } PreheatTimer; + #endif + #if ENABLED(BABYSTEPPING) + struct { + struct base_numeric_adjustment_t placeholder; + xyz_int_t rel; + #if HAS_MULTI_EXTRUDER + bool link_nozzles; + #endif + bool show_offsets; + } NudgeNozzle; + #endif +}; + +extern screen_data_t screen_data; diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.cpp new file mode 100644 index 0000000..5841c38 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.cpp @@ -0,0 +1,139 @@ +/*************** + * screens.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) +#include "screens.h" +#include "screen_data.h" + +tiny_timer_t refresh_timer; +screen_data_t screen_data; + +SCREEN_TABLE { + DECL_SCREEN(BootScreen), + #if NUM_LANGUAGES > 1 + DECL_SCREEN(LanguageMenu), + #endif + DECL_SCREEN(TouchCalibrationScreen), + DECL_SCREEN(StatusScreen), + DECL_SCREEN(MainMenu), + DECL_SCREEN(TuneMenu), + DECL_SCREEN(AdvancedSettingsMenu), + DECL_SCREEN(AlertDialogBox), + DECL_SCREEN(ConfirmUserRequestAlertBox), + DECL_SCREEN(RestoreFailsafeDialogBox), + DECL_SCREEN(SaveSettingsDialogBox), + DECL_SCREEN(ConfirmStartPrintDialogBox), + DECL_SCREEN(ConfirmAbortPrintDialogBox), + #if ENABLED(CALIBRATION_GCODE) + DECL_SCREEN(ConfirmAutoCalibrationDialogBox), + #endif + #if ENABLED(CUSTOM_USER_MENUS) + DECL_SCREEN(CustomUserMenus), + #endif + DECL_SCREEN(SpinnerDialogBox), + DECL_SCREEN(AboutScreen), + #if ENABLED(PRINTCOUNTER) + DECL_SCREEN(StatisticsScreen), + #endif + #if ENABLED(BABYSTEPPING) + DECL_SCREEN(NudgeNozzleScreen), + #endif + DECL_SCREEN(MoveAxisScreen), + DECL_SCREEN(StepsScreen), + #if HAS_TRINAMIC_CONFIG + DECL_SCREEN(StepperCurrentScreen), + DECL_SCREEN(StepperBumpSensitivityScreen), + #endif + #if HAS_LEVELING + DECL_SCREEN(LevelingMenu), + #if HAS_BED_PROBE + DECL_SCREEN(ZOffsetScreen), + #endif + #if HAS_MESH + DECL_SCREEN(BedMeshScreen), + #endif + #endif + #if HAS_MULTI_HOTEND + DECL_SCREEN(NozzleOffsetScreen), + #endif + #if ENABLED(BACKLASH_GCODE) + DECL_SCREEN(BacklashCompensationScreen), + #endif + DECL_SCREEN(FeedratePercentScreen), + DECL_SCREEN(MaxVelocityScreen), + DECL_SCREEN(MaxAccelerationScreen), + DECL_SCREEN(DefaultAccelerationScreen), + #if HAS_JUNCTION_DEVIATION + DECL_SCREEN(JunctionDeviationScreen), + #else + DECL_SCREEN(JerkScreen), + #endif + #if ENABLED(CASE_LIGHT_ENABLE) + DECL_SCREEN(CaseLightScreen), + #endif + #if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR) + DECL_SCREEN(FilamentMenu), + #endif + #if ENABLED(FILAMENT_RUNOUT_SENSOR) + DECL_SCREEN(FilamentRunoutScreen), + #endif + #if ENABLED(LIN_ADVANCE) + DECL_SCREEN(LinearAdvanceScreen), + #endif + DECL_SCREEN(TemperatureScreen), + DECL_SCREEN(ChangeFilamentScreen), + DECL_SCREEN(InterfaceSettingsScreen), + DECL_SCREEN(InterfaceSoundsScreen), + DECL_SCREEN(LockScreen), + #if ENABLED(SDSUPPORT) + DECL_SCREEN(FilesScreen), + #endif + DECL_SCREEN(EndstopStatesScreen), + #if ENABLED(TOUCH_UI_LULZBOT_BIO) + DECL_SCREEN(BioPrintingDialogBox), + DECL_SCREEN(BioConfirmHomeXYZ), + DECL_SCREEN(BioConfirmHomeE), + #endif + #if ENABLED(TOUCH_UI_COCOA_PRESS) + DECL_SCREEN(PreheatMenu), + DECL_SCREEN(PreheatTimerScreen), + DECL_SCREEN(UnloadCartridgeScreen), + DECL_SCREEN(LoadChocolateScreen), + DECL_SCREEN(MoveXYZScreen), + DECL_SCREEN(MoveEScreen), + #endif + #if ENABLED(TOUCH_UI_DEVELOPER_MENU) + DECL_SCREEN(DeveloperMenu), + DECL_SCREEN(ConfirmEraseFlashDialogBox), + DECL_SCREEN(WidgetsScreen), + DECL_SCREEN(TouchRegistersScreen), + DECL_SCREEN(StressTestScreen), + #endif + DECL_SCREEN(MediaPlayerScreen), + DECL_SCREEN(DisplayTuningScreen) +}; + +SCREEN_TABLE_POST + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h new file mode 100644 index 0000000..51fc76f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/screens.h @@ -0,0 +1,911 @@ +/************* + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +#include "../ftdi_eve_lib/ftdi_eve_lib.h" +#include "../language/language.h" +#include "../theme/theme.h" +#include "string_format.h" + +#ifndef BED_LEVELING_COMMANDS + #define BED_LEVELING_COMMANDS "G29" +#endif + +extern tiny_timer_t refresh_timer; + +/********************************* 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, + #if HAS_LEVELING + LEVELING_SCREEN_CACHE, + #if HAS_BED_PROBE + ZOFFSET_SCREEN_CACHE, + #endif + #if HAS_MESH + BED_MESH_SCREEN_CACHE, + #endif + #endif + #if ENABLED(BABYSTEPPING) + ADJUST_OFFSETS_SCREEN_CACHE, + #endif + #if HAS_TRINAMIC_CONFIG + STEPPER_CURRENT_SCREEN_CACHE, + STEPPER_BUMP_SENSITIVITY_SCREEN_CACHE, + #endif + #if HAS_MULTI_HOTEND + NOZZLE_OFFSET_SCREEN_CACHE, + #endif + #if ENABLED(BACKLASH_GCODE) + BACKLASH_COMPENSATION_SCREEN_CACHE, + #endif + #if HAS_JUNCTION_DEVIATION + JUNC_DEV_SCREEN_CACHE, + #else + JERK_SCREEN_CACHE, + #endif + #if ENABLED(CASE_LIGHT_ENABLE) + CASE_LIGHT_SCREEN_CACHE, + #endif + #if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR) + FILAMENT_MENU_CACHE, + #endif + #if ENABLED(LIN_ADVANCE) + LINEAR_ADVANCE_SCREEN_CACHE, + #endif + #if ENABLED(FILAMENT_RUNOUT_SENSOR) + FILAMENT_RUNOUT_SCREEN_CACHE, + #endif + #if ENABLED(TOUCH_UI_LULZBOT_BIO) + PRINTING_SCREEN_CACHE, + #endif + #if ENABLED(TOUCH_UI_COCOA_PRESS) + PREHEAT_MENU_CACHE, + PREHEAT_TIMER_SCREEN_CACHE, + UNLOAD_CARTRIDGE_SCREEN_CACHE, + LOAD_CHOCOLATE_SCREEN_CACHE, + MOVE_XYZ_SCREEN_CACHE, + MOVE_E_SCREEN_CACHE, + #endif + #if ENABLED(SDSUPPORT) + FILES_SCREEN_CACHE, + #endif + #if ENABLED(CUSTOM_USER_MENUS) + CUSTOM_USER_MENUS_SCREEN_CACHE, + #endif + CHANGE_FILAMENT_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 *************************/ + +class BaseScreen : public UIScreen { + protected: + #if LCD_TIMEOUT_TO_STATUS > 0 + static uint32_t last_interaction; + #endif + + static bool buttonIsPressed(uint8_t tag); + + public: + static bool buttonStyleCallback(CommandProcessor &, uint8_t, uint8_t &, uint16_t &, bool); + + static void reset_menu_timeout(); + + static void onEntry(); + static void onIdle(); +}; + +class BootScreen : public BaseScreen, public UncachedScreen { + private: + static void showSplashScreen(); + public: + static void onRedraw(draw_mode_t); + static void onIdle(); +}; + +class AboutScreen : public BaseScreen, public UncachedScreen { + public: + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); +}; + +#if ENABLED(PRINTCOUNTER) + class StatisticsScreen : public BaseScreen, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; +#endif + +class KillScreen { + // The KillScreen is behaves differently than the + // others, so we do not bother extending UIScreen. + public: + static void show(const char*); +}; + +class DialogBoxBaseClass : public BaseScreen { + protected: + template<typename T> static void drawMessage(const T, int16_t font = 0); + static void drawYesNoButtons(uint8_t default_btn = 0); + static void drawOkayButton(); + static void drawSpinner(); + static void drawButton(const progmem_str); + + static void onRedraw(draw_mode_t) {}; + public: + static bool onTouchEnd(uint8_t tag); + static void onIdle(); +}; + +class AlertDialogBox : public DialogBoxBaseClass, public CachedScreen<ALERT_BOX_CACHE,ALERT_BOX_DL_SIZE> { + public: + static void onEntry(); + static void onRedraw(draw_mode_t); + template<typename T> static void show(T); + template<typename T> static void showError(T); + static void hide(); +}; + +class RestoreFailsafeDialogBox : public DialogBoxBaseClass, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); +}; + +class SaveSettingsDialogBox : public DialogBoxBaseClass, public UncachedScreen { + private: + static bool needs_save; + + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + + static void promptToSaveSettings(); + static void settingsChanged() {needs_save = true;} +}; + +class ConfirmStartPrintDialogBox : public DialogBoxBaseClass, public UncachedScreen { + private: + inline static const char *getShortFilename() {return getFilename(false);} + inline static const char *getLongFilename() {return getFilename(true);} + + static const char *getFilename(bool longName); + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t); + + static void show(uint8_t file_index); +}; + +class ConfirmAbortPrintDialogBox : public DialogBoxBaseClass, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); +}; + +#if ENABLED(CALIBRATION_GCODE) +class ConfirmAutoCalibrationDialogBox : public DialogBoxBaseClass, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); +}; +#endif + +class ConfirmUserRequestAlertBox : public AlertDialogBox { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t); + static void hide(); + static void show(const char*); +}; + +#if ENABLED(CUSTOM_USER_MENUS) + class CustomUserMenus : public BaseScreen, public CachedScreen<CUSTOM_USER_MENUS_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; +#endif + +class SpinnerDialogBox : public DialogBoxBaseClass, public CachedScreen<SPINNER_CACHE,SPINNER_DL_SIZE> { + public: + static void onRedraw(draw_mode_t); + static void onIdle(); + + static void show(const progmem_str); + static void hide(); + static void enqueueAndWait_P(const progmem_str commands); + static void enqueueAndWait_P(const progmem_str message, const progmem_str commands); +}; + +#if NONE(TOUCH_UI_LULZBOT_BIO, TOUCH_UI_COCOA_PRESS) +class StatusScreen : public BaseScreen, public CachedScreen<STATUS_SCREEN_CACHE,STATUS_SCREEN_DL_SIZE> { + private: + static void draw_axis_position(draw_mode_t); + static void draw_temperature(draw_mode_t); + static void draw_progress(draw_mode_t); + static void draw_interaction_buttons(draw_mode_t); + static void draw_status_message(draw_mode_t, const char * const); + static void _format_time(char *outstr, uint32_t time); + public: + static void loadBitmaps(); + static void setStatusMessage(const char *); + static void setStatusMessage(progmem_str); + static void onRedraw(draw_mode_t); + static void onStartup(); + static void onEntry(); + static void onIdle(); + static bool onTouchEnd(uint8_t tag); +}; +#else + class StatusScreen : public BaseScreen, public CachedScreen<STATUS_SCREEN_CACHE> { + 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(progmem_str); + + 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(); + + }; +#endif + +#if ENABLED(TOUCH_UI_LULZBOT_BIO) + class BioPrintingDialogBox : public BaseScreen, public CachedScreen<PRINTING_SCREEN_CACHE,PRINTING_SCREEN_DL_SIZE> { + 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(progmem_str); + + static void onIdle(); + static bool onTouchEnd(uint8_t tag); + }; + + class BioConfirmHomeXYZ : public DialogBoxBaseClass, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; + + class BioConfirmHomeE : public DialogBoxBaseClass, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; +#endif + +class MainMenu : public BaseScreen, public CachedScreen<MENU_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); +}; + +class TuneMenu : public BaseScreen, public CachedScreen<TUNE_SCREEN_CACHE> { + private: + static void pausePrint(); + static void resumePrint(); + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); +}; + +class TouchCalibrationScreen : public BaseScreen, public UncachedScreen { + public: + static void onRefresh(); + static void onEntry(); + static void onRedraw(draw_mode_t); + static void onIdle(); +}; + +class TouchRegistersScreen : public BaseScreen, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); +}; + +class AdvancedSettingsMenu : public BaseScreen, public CachedScreen<ADVANCED_SETTINGS_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); +}; + +class ChangeFilamentScreen : public BaseScreen, public CachedScreen<CHANGE_FILAMENT_SCREEN_CACHE> { + private: + static uint8_t getSoftenTemp(); + static ExtUI::extruder_t getExtruder(); + static void drawTempGradient(uint16_t x, uint16_t y, uint16_t w, uint16_t h); + static uint32_t getTempColor(uint32_t temp); + static void doPurge(); + public: + static void onEntry(); + static void onExit(); + static void onRedraw(draw_mode_t); + static bool onTouchStart(uint8_t tag); + static bool onTouchEnd(uint8_t tag); + static bool onTouchHeld(uint8_t tag); + static void onIdle(); +}; + +class BaseNumericAdjustmentScreen : public BaseScreen { + public: + enum precision_default_t { + DEFAULT_LOWEST, + DEFAULT_MIDRANGE, + DEFAULT_HIGHEST + }; + + protected: + class widgets_t { + private: + draw_mode_t _what; + uint8_t _line; + uint32_t _color; + uint8_t _decimals; + progmem_str _units; + enum style_t { + BTN_NORMAL, + BTN_ACTION, + BTN_TOGGLE, + BTN_DISABLED, + TEXT_AREA, + TEXT_LABEL + } _style; + + protected: + void _draw_increment_btn(CommandProcessor &, uint8_t line, const uint8_t tag); + void _button(CommandProcessor &, uint8_t tag, int16_t x, int16_t y, int16_t w, int16_t h, progmem_str, bool enabled = true, bool highlight = false); + void _button_style(CommandProcessor &cmd, style_t style); + public: + widgets_t(draw_mode_t); + + widgets_t &color(uint32_t color) {_color = color; return *this;} + widgets_t &units(progmem_str units) {_units = units; return *this;} + widgets_t &draw_mode(draw_mode_t what) {_what = what; return *this;} + widgets_t &precision(uint8_t decimals, precision_default_t = DEFAULT_HIGHEST); + + void heading (progmem_str label); + void adjuster_sram_val (uint8_t tag, progmem_str label, const char *value, bool is_enabled = true); + void adjuster (uint8_t tag, progmem_str label, const char *value, bool is_enabled = true); + void adjuster (uint8_t tag, progmem_str label, float value=0, bool is_enabled = true); + void button (uint8_t tag, progmem_str label, bool is_enabled = true); + void text_field (uint8_t tag, progmem_str label, const char *value, bool is_enabled = true); + void two_buttons (uint8_t tag1, progmem_str label1, + uint8_t tag2, progmem_str label2, bool is_enabled = true); + void toggle (uint8_t tag, progmem_str label, bool value, bool is_enabled = true); + void home_buttons (uint8_t tag); + void increments (); + }; + + static float getIncrement(); + + public: + static void onEntry(); + static bool onTouchEnd(uint8_t tag); +}; + +class BaseMoveAxisScreen : public BaseNumericAdjustmentScreen { + private: + static float getManualFeedrate(uint8_t axis, float increment_mm); + public: + static void setManualFeedrate(ExtUI::axis_t, float increment_mm); + static void setManualFeedrate(ExtUI::extruder_t, float increment_mm); + + static void onEntry(); + static bool onTouchHeld(uint8_t tag); +}; + +class MoveAxisScreen : public BaseMoveAxisScreen, public CachedScreen<MOVE_AXIS_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static void onIdle(); +}; + +class StepsScreen : public BaseNumericAdjustmentScreen, public CachedScreen<STEPS_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); +}; + +#if HAS_TRINAMIC_CONFIG + class StepperCurrentScreen : public BaseNumericAdjustmentScreen, public CachedScreen<STEPPER_CURRENT_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; + + class StepperBumpSensitivityScreen : public BaseNumericAdjustmentScreen, public CachedScreen<STEPPER_BUMP_SENSITIVITY_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; +#endif + +#if HAS_MULTI_HOTEND + class NozzleOffsetScreen : public BaseNumericAdjustmentScreen, public CachedScreen<NOZZLE_OFFSET_SCREEN_CACHE> { + public: + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; +#endif + +#if HAS_LEVELING + + class LevelingMenu : public BaseScreen, public CachedScreen<LEVELING_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; + + #if HAS_BED_PROBE + class ZOffsetScreen : public BaseNumericAdjustmentScreen, public CachedScreen<ZOFFSET_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; + #endif + + #if HAS_MESH + + class BedMeshScreen : public BaseScreen, public CachedScreen<BED_MESH_SCREEN_CACHE> { + private: + enum MeshOpts { + USE_POINTS = 0x01, + USE_COLORS = 0x02, + USE_TAGS = 0x04, + USE_HIGHLIGHT = 0x08, + USE_AUTOSCALE = 0x10 + }; + + static uint8_t pointToTag(uint8_t x, uint8_t y); + static bool tagToPoint(uint8_t tag, uint8_t &x, uint8_t &y); + static float getHightlightedValue(); + static void drawHighlightedPointValue(); + static void drawMesh(int16_t x, int16_t y, int16_t w, int16_t h, ExtUI::bed_mesh_t data, uint8_t opts, float autoscale_max = 0.1); + + public: + static void onMeshUpdate(const int8_t x, const int8_t y, const float val); + static void onMeshUpdate(const int8_t x, const int8_t y, const ExtUI::probe_state_t); + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchStart(uint8_t tag); + static bool onTouchEnd(uint8_t tag); + + static void startMeshProbe(); + }; + + #endif // HAS_MESH + +#endif // HAS_LEVELING + +#if ENABLED(BABYSTEPPING) + class NudgeNozzleScreen : public BaseNumericAdjustmentScreen, public CachedScreen<ADJUST_OFFSETS_SCREEN_CACHE> { + public: + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + static bool onTouchHeld(uint8_t tag); + static void onIdle(); + }; +#endif + +#if ENABLED(BACKLASH_GCODE) + class BacklashCompensationScreen : public BaseNumericAdjustmentScreen, public CachedScreen<BACKLASH_COMPENSATION_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; +#endif + +class FeedratePercentScreen : public BaseNumericAdjustmentScreen, public CachedScreen<MAX_FEEDRATE_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); +}; + +class MaxVelocityScreen : public BaseNumericAdjustmentScreen, public CachedScreen<MAX_VELOCITY_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); +}; + +class MaxAccelerationScreen : public BaseNumericAdjustmentScreen, public CachedScreen<MAX_ACCELERATION_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); +}; + +class DefaultAccelerationScreen : public BaseNumericAdjustmentScreen, public CachedScreen<DEFAULT_ACCELERATION_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); +}; + +#if HAS_JUNCTION_DEVIATION + class JunctionDeviationScreen : public BaseNumericAdjustmentScreen, public CachedScreen<JUNC_DEV_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; +#else + class JerkScreen : public BaseNumericAdjustmentScreen, public CachedScreen<JERK_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; +#endif + +#if ENABLED(CASE_LIGHT_ENABLE) + class CaseLightScreen : public BaseNumericAdjustmentScreen, public CachedScreen<CASE_LIGHT_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; +#endif + +#if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR) + class FilamentMenu : public BaseNumericAdjustmentScreen, public CachedScreen<FILAMENT_MENU_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; +#endif + +#if ENABLED(FILAMENT_RUNOUT_SENSOR) + class FilamentRunoutScreen : public BaseNumericAdjustmentScreen, public CachedScreen<FILAMENT_RUNOUT_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; +#endif + +#if ENABLED(LIN_ADVANCE) + class LinearAdvanceScreen : public BaseNumericAdjustmentScreen, public CachedScreen<LINEAR_ADVANCE_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); + }; +#endif + +class TemperatureScreen : public BaseNumericAdjustmentScreen, public CachedScreen<TEMPERATURE_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); +}; + +class InterfaceSoundsScreen : public BaseScreen, public CachedScreen<INTERFACE_SOUNDS_SCREEN_CACHE> { + public: + enum event_t { + PRINTING_STARTED = 0, + PRINTING_FINISHED = 1, + PRINTING_FAILED = 2, + + NUM_EVENTS + }; + + private: + friend class InterfaceSettingsScreen; + + static uint8_t event_sounds[NUM_EVENTS]; + + static const char* getSoundSelection(event_t); + static void toggleSoundSelection(event_t); + static void setSoundSelection(event_t, const FTDI::SoundPlayer::sound_t*); + + public: + static void playEventSound(event_t, FTDI::play_mode_t = FTDI::PLAY_ASYNCHRONOUS); + + static void defaultSettings(); + + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchStart(uint8_t tag); + static bool onTouchEnd(uint8_t tag); + static void onIdle(); +}; + +class InterfaceSettingsScreen : public BaseScreen, public CachedScreen<INTERFACE_SETTINGS_SCREEN_CACHE> { + private: + struct persistent_data_t { + uint32_t touch_transform_a; + uint32_t touch_transform_b; + uint32_t touch_transform_c; + uint32_t touch_transform_d; + uint32_t touch_transform_e; + uint32_t touch_transform_f; + uint16_t passcode; + uint8_t display_brightness; + int8_t display_h_offset_adj; + int8_t display_v_offset_adj; + uint8_t sound_volume; + uint8_t bit_flags; + uint8_t event_sounds[InterfaceSoundsScreen::NUM_EVENTS]; + }; + + public: + #ifdef ARCHIM2_SPI_FLASH_EEPROM_BACKUP_SIZE + static bool backupEEPROM(); + #endif + + static void saveSettings(char *); + static void loadSettings(const char *); + static void defaultSettings(); + static void failSafeSettings(); + + static void onStartup(); + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchStart(uint8_t tag); + static bool onTouchEnd(uint8_t tag); + static void onIdle(); +}; + +class LockScreen : public BaseScreen, public CachedScreen<LOCK_SCREEN_CACHE> { + private: + friend InterfaceSettingsScreen; + + static uint16_t passcode; + + static char & message_style(); + static uint16_t compute_checksum(); + static void onPasscodeEntered(); + public: + static bool is_enabled(); + static void check_passcode(); + static void enable(); + static void disable(); + + static void set_hash(uint16_t pass) {passcode = pass;}; + static uint16_t get_hash() {return passcode;}; + + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); +}; + +#if ENABLED(SDSUPPORT) + + class FilesScreen : public BaseScreen, public CachedScreen<FILES_SCREEN_CACHE, FILE_SCREEN_DL_SIZE> { + private: + #if ENABLED(TOUCH_UI_PORTRAIT) + static constexpr uint8_t header_h = 2; + static constexpr uint8_t footer_h = 2; + static constexpr uint8_t files_per_page = 11; + #else + static constexpr uint8_t header_h = 1; + static constexpr uint8_t footer_h = 1; + static constexpr uint8_t files_per_page = 6; + #endif + + static uint8_t getTagForLine(uint8_t line) {return line + 2;} + static uint8_t getLineForTag(uint8_t tag) {return tag - 2;} + static uint16_t getFileForTag(uint8_t tag); + static uint16_t getSelectedFileIndex(); + + inline static const char *getSelectedShortFilename() {return getSelectedFilename(false);} + inline static const char *getSelectedLongFilename() {return getSelectedFilename(true);} + static const char *getSelectedFilename(bool longName); + + static void drawFileButton(const char* filename, uint8_t tag, bool is_dir, bool is_highlighted); + static void drawFileList(); + static void drawHeader(); + static void drawFooter(); + static void drawSelectedFile(); + + static void gotoPage(uint8_t); + public: + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + static void onIdle(); + }; + +#endif // SDSUPPORT + +class EndstopStatesScreen : public BaseScreen, public UncachedScreen { + public: + static void onEntry(); + static void onExit(); + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + static void onIdle(); +}; + +class DisplayTuningScreen : public BaseNumericAdjustmentScreen, public CachedScreen<DISPLAY_TIMINGS_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchHeld(uint8_t tag); +}; + +#if ENABLED(TOUCH_UI_DEVELOPER_MENU) + + class DeveloperMenu : public BaseScreen, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; + + class ConfirmEraseFlashDialogBox : public DialogBoxBaseClass, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; + + class WidgetsScreen : public BaseScreen, public UncachedScreen { + public: + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchStart(uint8_t tag); + static void onIdle(); + }; + + class StressTestScreen : public BaseScreen, public UncachedScreen { + private: + static void drawDots(uint16_t x, uint16_t y, uint16_t h, uint16_t v); + static bool watchDogTestNow(); + static void recursiveLockup(); + static void iterativeLockup(); + static void runTestOnBootup(bool enable); + + public: + static void startupCheck(); + + static void onEntry(); + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + static void onIdle(); + }; + +#endif // TOUCH_UI_DEVELOPER_MENU + +class MediaPlayerScreen : public BaseScreen, public UncachedScreen { + private: + typedef int16_t media_streamer_func_t(void *obj, void *buff, size_t bytes); + + public: + static bool playCardMedia(); + static bool playBootMedia(); + + static void onEntry(); + static void onRedraw(draw_mode_t); + + static void playStream(void *obj, media_streamer_func_t*); +}; + +#if NUM_LANGUAGES > 1 + class LanguageMenu : public BaseScreen, public UncachedScreen { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; +#endif + +#if ENABLED(TOUCH_UI_COCOA_PRESS) + + class PreheatMenu : public BaseScreen, public CachedScreen<PREHEAT_MENU_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + }; + + class PreheatTimerScreen : public BaseScreen, public CachedScreen<PREHEAT_TIMER_SCREEN_CACHE> { + 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, progmem_str 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); + }; + + class UnloadCartridgeScreen : public BaseScreen, public CachedScreen<UNLOAD_CARTRIDGE_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + static bool onTouchHeld(uint8_t tag); + }; + + class LoadChocolateScreen : public BaseScreen, public CachedScreen<LOAD_CHOCOLATE_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static bool onTouchEnd(uint8_t tag); + static bool onTouchHeld(uint8_t tag); + }; + + class MoveXYZScreen : public BaseMoveAxisScreen, public CachedScreen<MOVE_XYZ_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static void onIdle(); + }; + + class MoveEScreen : public BaseMoveAxisScreen, public CachedScreen<MOVE_E_SCREEN_CACHE> { + public: + static void onRedraw(draw_mode_t); + static void onIdle(); + }; + +#endif // TOUCH_UI_COCOA_PRESS diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/spinner_dialog_box.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/spinner_dialog_box.cpp new file mode 100644 index 0000000..2318a0d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/spinner_dialog_box.cpp @@ -0,0 +1,68 @@ +/************************** + * spinner_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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" +#include "screen_data.h" + +using namespace FTDI; +using namespace ExtUI; + +void SpinnerDialogBox::onRedraw(draw_mode_t) { +} + +void SpinnerDialogBox::show(const progmem_str message) { + drawMessage(message); + drawSpinner(); + storeBackground(); + screen_data.SpinnerDialog.auto_hide = false; +} + +void SpinnerDialogBox::hide() { + CommandProcessor cmd; + cmd.stop().execute(); +} + +void SpinnerDialogBox::enqueueAndWait_P(const progmem_str commands) { + enqueueAndWait_P(GET_TEXT_F(MSG_PLEASE_WAIT), commands); +} + +void SpinnerDialogBox::enqueueAndWait_P(const progmem_str message, const progmem_str commands) { + show(message); + GOTO_SCREEN(SpinnerDialogBox); + ExtUI::injectCommands_P((const char*)commands); + screen_data.SpinnerDialog.auto_hide = true; +} + +void SpinnerDialogBox::onIdle() { + reset_menu_timeout(); + if (screen_data.SpinnerDialog.auto_hide && !commandsInQueue()) { + screen_data.SpinnerDialog.auto_hide = false; + hide(); + GOTO_PREVIOUS(); + } +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/statistics_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/statistics_screen.cpp new file mode 100644 index 0000000..0e224da --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/statistics_screen.cpp @@ -0,0 +1,78 @@ +/************************* + * statistics_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, PRINTCOUNTER) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +#define GRID_COLS 4 +#define GRID_ROWS 7 + +void StatisticsScreen::onRedraw(draw_mode_t what) { + CommandProcessor cmd; + + if (what & BACKGROUND) { + char buffer[21]; + + cmd.cmd(CLEAR_COLOR_RGB(Theme::bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0) + + .font(Theme::font_medium) + .text(BTN_POS(1,1), BTN_SIZE(4,1), GET_TEXT_F(MSG_INFO_STATS_MENU)) + .font(Theme::font_small) + .tag(0) + .text(BTN_POS(1,2), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_PRINT_COUNT), OPT_RIGHTX | OPT_CENTERY) + .text(BTN_POS(1,3), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_COMPLETED_PRINTS), OPT_RIGHTX | OPT_CENTERY) + .text(BTN_POS(1,4), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_PRINT_TIME), OPT_RIGHTX | OPT_CENTERY) + .text(BTN_POS(1,5), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_PRINT_LONGEST), OPT_RIGHTX | OPT_CENTERY) + .text(BTN_POS(1,6), BTN_SIZE(2,1), GET_TEXT_F(MSG_INFO_PRINT_FILAMENT), OPT_RIGHTX | OPT_CENTERY); + // Don't chain the following, it causes strange issues with evaluation ordering! + cmd.text(BTN_POS(3,2), BTN_SIZE(2,1), getTotalPrints_str(buffer)); + cmd.text(BTN_POS(3,3), BTN_SIZE(2,1), getFinishedPrints_str(buffer)); + cmd.text(BTN_POS(3,4), BTN_SIZE(2,1), getTotalPrintTime_str(buffer)); + cmd.text(BTN_POS(3,5), BTN_SIZE(2,1), getLongestPrint_str(buffer)); + cmd.text(BTN_POS(3,6), BTN_SIZE(2,1), getFilamentUsed_str(buffer)); + } + + if (what & FOREGROUND) { + cmd.font(Theme::font_medium) + .colors(action_btn) + .tag(1).button(BTN_POS(1,7), BTN_SIZE(4,1), GET_TEXT_F(MSG_BACK)); + } +} + +bool StatisticsScreen::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); return true; + default: return false; + } +} + +#endif // TOUCH_UI_FTDI_EVE && PRINTCOUNTER diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/status_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/status_screen.cpp new file mode 100644 index 0000000..51f5034 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/status_screen.cpp @@ -0,0 +1,465 @@ +/********************* + * status_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) && NONE(TOUCH_UI_LULZBOT_BIO, TOUCH_UI_COCOA_PRESS) + +#include "screens.h" +#include "screen_data.h" + +#include "../archim2-flash/flash_storage.h" + +using namespace FTDI; +using namespace Theme; + +#if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_ROWS 16 +#else + #define GRID_ROWS 16 +#endif + +void StatusScreen::draw_axis_position(draw_mode_t what) { + CommandProcessor cmd; + + #define GRID_COLS 3 + + #if ENABLED(TOUCH_UI_PORTRAIT) + #define X_LBL_POS BTN_POS(1, 9), BTN_SIZE(1,2) + #define Y_LBL_POS BTN_POS(1,11), BTN_SIZE(1,2) + #define Z_LBL_POS BTN_POS(1,13), BTN_SIZE(1,2) + #define X_VAL_POS BTN_POS(2, 9), BTN_SIZE(2,2) + #define Y_VAL_POS BTN_POS(2,11), BTN_SIZE(2,2) + #define Z_VAL_POS BTN_POS(2,13), BTN_SIZE(2,2) + #else + #define X_LBL_POS BTN_POS(1, 9), BTN_SIZE(1,2) + #define Y_LBL_POS BTN_POS(2, 9), BTN_SIZE(1,2) + #define Z_LBL_POS BTN_POS(3, 9), BTN_SIZE(1,2) + #define X_VAL_POS BTN_POS(1,11), BTN_SIZE(1,2) + #define Y_VAL_POS BTN_POS(2,11), BTN_SIZE(1,2) + #define Z_VAL_POS BTN_POS(3,11), BTN_SIZE(1,2) + #endif + + #define _UNION_POS(x1,y1,w1,h1,x2,y2,w2,h2) x1,y1,max(x1+w1,x2+w2)-x1,max(y1+h1,y2+h2)-y1 + #define UNION_POS(p1, p2) _UNION_POS(p1, p2) + + if (what & BACKGROUND) { + cmd.tag(6) + .fgcolor(Theme::axis_label) + .font(Theme::font_large) + .button(UNION_POS(X_LBL_POS, X_VAL_POS), F(""), OPT_FLAT) + .button(UNION_POS(Y_LBL_POS, Y_VAL_POS), F(""), OPT_FLAT) + .button(UNION_POS(Z_LBL_POS, Z_VAL_POS), F(""), OPT_FLAT) + .font(Theme::font_medium) + .fgcolor(Theme::x_axis) .button(X_VAL_POS, F(""), OPT_FLAT) + .fgcolor(Theme::y_axis) .button(Y_VAL_POS, F(""), OPT_FLAT) + .fgcolor(Theme::z_axis) .button(Z_VAL_POS, F(""), OPT_FLAT) + .font(Theme::font_small) + .text ( X_LBL_POS, GET_TEXT_F(MSG_AXIS_X)) + .text ( Y_LBL_POS, GET_TEXT_F(MSG_AXIS_Y)) + .text ( Z_LBL_POS, GET_TEXT_F(MSG_AXIS_Z)) + .colors(normal_btn); + } + + if (what & FOREGROUND) { + using namespace ExtUI; + char x_str[15]; + char y_str[15]; + char z_str[15]; + + if (isAxisPositionKnown(X)) + format_position(x_str, getAxisPosition_mm(X)); + else + strcpy_P(x_str, PSTR("?")); + + if (isAxisPositionKnown(Y)) + format_position(y_str, getAxisPosition_mm(Y)); + else + strcpy_P(y_str, PSTR("?")); + + if (isAxisPositionKnown(Z)) + format_position(z_str, getAxisPosition_mm(Z), 2); + else + strcpy_P(z_str, PSTR("?")); + + cmd.tag(6) + .font(Theme::font_medium) + .text(X_VAL_POS, x_str) + .text(Y_VAL_POS, y_str) + .text(Z_VAL_POS, z_str); + } + + #undef GRID_COLS +} + +#if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_COLS 8 +#else + #define GRID_COLS 12 +#endif + +void StatusScreen::draw_temperature(draw_mode_t what) { + using namespace Theme; + + #define TEMP_RECT_1 BTN_POS(1,1), BTN_SIZE(4,4) + #define TEMP_RECT_2 BTN_POS(1,1), BTN_SIZE(8,2) + #define NOZ_1_POS BTN_POS(1,1), BTN_SIZE(4,2) + #define NOZ_2_POS BTN_POS(5,1), BTN_SIZE(4,2) + #define BED_POS BTN_POS(1,3), BTN_SIZE(4,2) + #define FAN_POS BTN_POS(5,3), BTN_SIZE(4,2) + + #define _ICON_POS(x,y,w,h) x, y, w/4, h + #define _TEXT_POS(x,y,w,h) x + w/4, y, w - w/4, h + #define ICON_POS(pos) _ICON_POS(pos) + #define TEXT_POS(pos) _TEXT_POS(pos) + + CommandProcessor cmd; + + if (what & BACKGROUND) { + cmd.font(Theme::font_small) + .tag(5) + .fgcolor(temp) .button(TEMP_RECT_1, F(""), OPT_FLAT) + .button(TEMP_RECT_2, F(""), OPT_FLAT) + .fgcolor(fan_speed).button(FAN_POS, F(""), OPT_FLAT) + .tag(0); + + // Draw Extruder Bitmap on Extruder Temperature Button + + cmd.tag(5) + .cmd (BITMAP_SOURCE(Extruder_Icon_Info)) + .cmd (BITMAP_LAYOUT(Extruder_Icon_Info)) + .cmd (BITMAP_SIZE (Extruder_Icon_Info)) + .icon(ICON_POS(NOZ_1_POS), Extruder_Icon_Info, icon_scale) + .icon(ICON_POS(NOZ_2_POS), Extruder_Icon_Info, icon_scale); + + // Draw Bed Heat Bitmap on Bed Heat Button + cmd.cmd (BITMAP_SOURCE(Bed_Heat_Icon_Info)) + .cmd (BITMAP_LAYOUT(Bed_Heat_Icon_Info)) + .cmd (BITMAP_SIZE (Bed_Heat_Icon_Info)) + .icon(ICON_POS(BED_POS), Bed_Heat_Icon_Info, icon_scale); + + // Draw Fan Percent Bitmap on Bed Heat Button + + cmd.cmd (BITMAP_SOURCE(Fan_Icon_Info)) + .cmd (BITMAP_LAYOUT(Fan_Icon_Info)) + .cmd (BITMAP_SIZE (Fan_Icon_Info)) + .icon(ICON_POS(FAN_POS), Fan_Icon_Info, icon_scale); + + TERN_(TOUCH_UI_USE_UTF8, load_utf8_bitmaps(cmd)); // Restore font bitmap handles + } + + if (what & FOREGROUND) { + using namespace ExtUI; + char e0_str[20], e1_str[20], bed_str[20], fan_str[20]; + + sprintf_P(fan_str, PSTR("%-3d %%"), int8_t(getActualFan_percent(FAN0))); + + if (isHeaterIdle(BED)) + format_temp_and_idle(bed_str, getActualTemp_celsius(BED)); + else + format_temp_and_temp(bed_str, getActualTemp_celsius(BED), getTargetTemp_celsius(BED)); + + if (isHeaterIdle(H0)) + format_temp_and_idle(e0_str, getActualTemp_celsius(H0)); + else + format_temp_and_temp(e0_str, getActualTemp_celsius(H0), getTargetTemp_celsius(H0)); + + #if HAS_MULTI_EXTRUDER + if (isHeaterIdle(H1)) + format_temp_and_idle(e1_str, getActualTemp_celsius(H1)); + else + format_temp_and_temp(e1_str, getActualTemp_celsius(H1), getTargetTemp_celsius(H1)); + #else + strcpy_P(e1_str, PSTR("-")); + #endif + + cmd.tag(5) + .font(font_medium) + .text(TEXT_POS(NOZ_1_POS), e0_str) + .text(TEXT_POS(NOZ_2_POS), e1_str) + .text(TEXT_POS(BED_POS), bed_str) + .text(TEXT_POS(FAN_POS), fan_str); + } +} + +void StatusScreen::_format_time(char *outstr, uint32_t time) { + const uint8_t hrs = time / 3600, + min = (time / 60) % 60, + sec = time % 60; + if (hrs) + sprintf_P(outstr, PSTR("%02d:%02d"), hrs, min); + else + sprintf_P(outstr, PSTR("%02d:%02ds"), min, sec); +} + +void StatusScreen::draw_progress(draw_mode_t what) { + using namespace ExtUI; + using namespace Theme; + + CommandProcessor cmd; + + #undef GRID_COLS + #if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_COLS 3 + #define PROGRESSZONE_POS BTN_POS(1,5), BTN_SIZE(3,2) + #define TIME_POS_X BTN_X(1) + #define TIME_POS_W BTN_W(1) + #define REMAINING_POS_X BTN_X(2) + #define REMAINING_POS_W BTN_W(1) + #define PROGRESS_POS_X BTN_X(3) + #define PROGRESS_POS_W BTN_W(1) + #define PROGRESSZONE_FIRSTLINE_Y BTN_Y(5) + #define PROGRESSBAR_POS BTN_POS(1,6), BTN_SIZE(3,1) + #else + #define GRID_COLS 6 + #define PROGRESSZONE_POS BTN_POS(5,1), BTN_SIZE(2,4) + #if ENABLED(SHOW_REMAINING_TIME) + #define TIME_POS BTN_POS(5,1), BTN_SIZE(1,2) + #define REMAINING_POS BTN_POS(6,1), BTN_SIZE(1,2) + #else + #define TIME_POS BTN_POS(5,1), BTN_SIZE(2,2) + #endif + #define PROGRESS_POS BTN_POS(5,3), BTN_SIZE(2,2) + #define PROGRESSBAR_POS BTN_POS(5,2), BTN_SIZE(2,2) + #endif + + if (what & BACKGROUND) { + cmd.tag(0).font(font_medium) + .fgcolor(progress).button(PROGRESSZONE_POS, F(""), OPT_FLAT); + } + + if (what & FOREGROUND) { + const uint32_t elapsed = getProgress_seconds_elapsed(); + char elapsed_str[10]; + _format_time(elapsed_str, elapsed); + + #if ENABLED(SHOW_REMAINING_TIME) + const uint32_t remaining = getProgress_seconds_remaining(); + char remaining_str[10]; + _format_time(remaining_str, remaining); + #endif + + const uint16_t current_progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, getProgress_permyriad(), getProgress_percent() * 100); + constexpr uint16_t progress_range = 10000U; + + const bool show_progress_bar = current_progress > 0 && current_progress < progress_range + 1; + if (show_progress_bar) { + cmd.tag(0).font(font_medium) + .bgcolor(progress) + .progress(PROGRESSBAR_POS, current_progress, progress_range, OPT_FLAT); + } + + char progress_str[10]; + sprintf_P(progress_str, + #if ENABLED(PRINT_PROGRESS_SHOW_DECIMALS) + PSTR("%3d.%02d%%"), uint8_t(current_progress / 100), current_progress % 100 + #else + PSTR("%3d%%"), uint8_t(current_progress / 100) + #endif + ); + + #if ENABLED(TOUCH_UI_PORTRAIT) + const uint16_t texts_pos_h = show_progress_bar ? (BTN_H(1)) : (BTN_H(2)); + cmd.font(font_medium) + .tag(7).text(TIME_POS_X, PROGRESSZONE_FIRSTLINE_Y, TIME_POS_W, texts_pos_h, elapsed_str) + #if ENABLED(SHOW_REMAINING_TIME) + .text(REMAINING_POS_X, PROGRESSZONE_FIRSTLINE_Y, REMAINING_POS_W, texts_pos_h, remaining_str) + #endif + .text(PROGRESS_POS_X, PROGRESSZONE_FIRSTLINE_Y, PROGRESS_POS_W, texts_pos_h, progress_str); + #else + cmd.font(font_medium) + .tag(7).text(TIME_POS, elapsed_str) + #if ENABLED(SHOW_REMAINING_TIME) + .text(REMAINING_POS, remaining_str) + #endif + .text(PROGRESS_POS, progress_str); + #endif + } + + #undef GRID_COLS +} + +void StatusScreen::draw_interaction_buttons(draw_mode_t what) { + #define GRID_COLS 4 + if (what & FOREGROUND) { + using namespace ExtUI; + + #if ENABLED(TOUCH_UI_PORTRAIT) + #define MEDIA_BTN_POS BTN_POS(1,15), BTN_SIZE(2,2) + #define MENU_BTN_POS BTN_POS(3,15), BTN_SIZE(2,2) + #else + #define MEDIA_BTN_POS BTN_POS(1,13), BTN_SIZE(2,4) + #define MENU_BTN_POS BTN_POS(3,13), BTN_SIZE(2,4) + #endif + + const bool has_media = isMediaInserted() && !isPrintingFromMedia(); + + CommandProcessor cmd; + cmd.colors(normal_btn) + .font(Theme::font_medium) + .colors(has_media ? action_btn : normal_btn) + .enabled(has_media) + .tag(3).button(MEDIA_BTN_POS, isPrintingFromMedia() ? GET_TEXT_F(MSG_PRINTING) : GET_TEXT_F(MSG_BUTTON_MEDIA)) + .colors(!has_media ? action_btn : normal_btn) + .tag(4).button(MENU_BTN_POS, GET_TEXT_F(MSG_BUTTON_MENU)); + } + #undef GRID_COLS +} + +void StatusScreen::draw_status_message(draw_mode_t what, const char* message) { + #define GRID_COLS 1 + + #if ENABLED(TOUCH_UI_PORTRAIT) + #define STATUS_POS BTN_POS(1,7), BTN_SIZE(1,2) + #else + #define STATUS_POS BTN_POS(1,5), BTN_SIZE(1,4) + #endif + + if (what & BACKGROUND) { + CommandProcessor cmd; + cmd.fgcolor(Theme::status_msg) + .tag(0) + .button(STATUS_POS, F(""), OPT_FLAT); + + draw_text_box(cmd, STATUS_POS, message, OPT_CENTER, font_large); + } + #undef GRID_COLS +} + +void StatusScreen::setStatusMessage(progmem_str message) { + char buff[strlen_P((const char * const)message)+1]; + strcpy_P(buff, (const char * const) message); + setStatusMessage((const char *) buff); +} + +void StatusScreen::setStatusMessage(const char* message) { + if (CommandProcessor::is_processing()) { + #if ENABLED(TOUCH_UI_DEBUG) + SERIAL_ECHO_MSG("Cannot update status message, command processor busy"); + #endif + return; + } + + CommandProcessor cmd; + cmd.cmd(CMD_DLSTART) + .cmd(CLEAR_COLOR_RGB(Theme::bg_color)) + .cmd(CLEAR(true,true,true)); + + draw_temperature(BACKGROUND); + draw_status_message(BACKGROUND, message); + draw_interaction_buttons(BACKGROUND); + draw_progress(BACKGROUND); + draw_axis_position(BACKGROUND); + + storeBackground(); + + #if ENABLED(TOUCH_UI_DEBUG) + SERIAL_ECHO_MSG("New status message: ", message); + #endif + + if (AT_SCREEN(StatusScreen)) { + current_screen.onRefresh(); + } +} + +void StatusScreen::loadBitmaps() { + // Load the bitmaps for the status screen + using namespace Theme; + constexpr uint32_t base = ftdi_memory_map::RAM_G; + CLCD::mem_write_pgm(base + TD_Icon_Info.RAMG_offset, TD_Icon, sizeof(TD_Icon)); + CLCD::mem_write_pgm(base + Extruder_Icon_Info.RAMG_offset, Extruder_Icon, sizeof(Extruder_Icon)); + CLCD::mem_write_pgm(base + Bed_Heat_Icon_Info.RAMG_offset, Bed_Heat_Icon, sizeof(Bed_Heat_Icon)); + CLCD::mem_write_pgm(base + Fan_Icon_Info.RAMG_offset, Fan_Icon, sizeof(Fan_Icon)); + + // Load fonts for internationalization + #if ENABLED(TOUCH_UI_USE_UTF8) + load_utf8_data(base + UTF8_FONT_OFFSET); + #endif +} + +void StatusScreen::onStartup() { + UIFlashStorage::initialize(); +} + +void StatusScreen::onRedraw(draw_mode_t what) { + if (what & FOREGROUND) { + draw_temperature(FOREGROUND); + draw_progress(FOREGROUND); + draw_axis_position(FOREGROUND); + draw_interaction_buttons(FOREGROUND); + } +} + +void StatusScreen::onEntry() { + BaseScreen::onEntry(); + onRefresh(); +} + +void StatusScreen::onIdle() { + if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) { + onRefresh(); + refresh_timer.start(); + } + BaseScreen::onIdle(); +} + +bool StatusScreen::onTouchEnd(uint8_t tag) { + using namespace ExtUI; + + switch (tag) { + #if ENABLED(SDSUPPORT) + case 3: GOTO_SCREEN(FilesScreen); break; + #endif + case 4: + if (isPrinting()) { + GOTO_SCREEN(TuneMenu); + } + else { + GOTO_SCREEN(MainMenu); + } + break; + case 5: GOTO_SCREEN(TemperatureScreen); break; + case 6: + if (isPrinting()) { + #if ENABLED(BABYSTEPPING) + GOTO_SCREEN(NudgeNozzleScreen); + #elif HAS_BED_PROBE + GOTO_SCREEN(ZOffsetScreen); + #else + return false; + #endif + } + else { + GOTO_SCREEN(MoveAxisScreen); + } + break; + case 7: GOTO_SCREEN(FeedratePercentScreen); break; + default: + return true; + } + // If a passcode is enabled, the LockScreen will prevent the + // user from proceeding. + LockScreen::check_passcode(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_bump_sensitivity_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_bump_sensitivity_screen.cpp new file mode 100644 index 0000000..84d76dc --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_bump_sensitivity_screen.cpp @@ -0,0 +1,59 @@ +/************************************** + * stepper_bump_sensiivity_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, HAS_TRINAMIC_CONFIG) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void StepperBumpSensitivityScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(0, BaseNumericAdjustmentScreen::DEFAULT_LOWEST); + w.heading( GET_TEXT_F(MSG_TMC_HOMING_THRS)); + w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getTMCBumpSensitivity(X), ENABLED(X_SENSORLESS)); + w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_Y), getTMCBumpSensitivity(Y), ENABLED(Y_SENSORLESS)); + w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Z), getTMCBumpSensitivity(Z), ENABLED(Z_SENSORLESS)); + w.increments(); +} + +bool StepperBumpSensitivityScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(TMCBumpSensitivity, X); break; + case 3: UI_INCREMENT(TMCBumpSensitivity, X); break; + case 4: UI_DECREMENT(TMCBumpSensitivity, Y); break; + case 5: UI_INCREMENT(TMCBumpSensitivity, Y); break; + case 6: UI_DECREMENT(TMCBumpSensitivity, Z); break; + case 7: UI_INCREMENT(TMCBumpSensitivity, Z); break; + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE && HAS_TRINAMIC_CONFIG diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_current_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_current_screen.cpp new file mode 100644 index 0000000..d6e36c1 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stepper_current_screen.cpp @@ -0,0 +1,127 @@ +/****************************** + * stepper_current_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, HAS_TRINAMIC_CONFIG) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void StepperCurrentScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(0); + w.units(GET_TEXT_F(MSG_UNITS_MILLIAMP)); + w.heading( GET_TEXT_F(MSG_TMC_CURRENT)); + #if AXIS_IS_TMC(X) + w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisCurrent_mA(X) ); + #endif + #if AXIS_IS_TMC(X2) + w.color(x_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_X2), getAxisCurrent_mA(X2) ); + #endif + #if AXIS_IS_TMC(Y) + w.color(y_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Y), getAxisCurrent_mA(Y) ); + #endif + #if AXIS_IS_TMC(Y2) + w.color(x_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_Y2), getAxisCurrent_mA(Y2) ); + #endif + #if AXIS_IS_TMC(Z) + w.color(z_axis) .adjuster(10, GET_TEXT_F(MSG_AXIS_Z), getAxisCurrent_mA(Z) ); + #endif + #if AXIS_IS_TMC(Z2) + w.color(z_axis) .adjuster(12, GET_TEXT_F(MSG_AXIS_Z2), getAxisCurrent_mA(Z2) ); + #endif + #if AXIS_IS_TMC(E0) + w.color(e_axis) .adjuster(14, GET_TEXT_F( + #if EXTRUDERS == 1 + MSG_AXIS_E + #else + MSG_AXIS_E1 + #endif + ), getAxisCurrent_mA(E0) ); + #endif + #if AXIS_IS_TMC(E1) + w.color(e_axis).adjuster(16, GET_TEXT_F(MSG_AXIS_E2), getAxisCurrent_mA(E1) ); + #endif + #if AXIS_IS_TMC(E2) + w.color(e_axis).adjuster(18, GET_TEXT_F(MSG_AXIS_E3), getAxisCurrent_mA(E2) ); + #endif + #if AXIS_IS_TMC(E3) + w.color(e_axis).adjuster(20, GET_TEXT_F(MSG_AXIS_E4), getAxisCurrent_mA(E3) ); + #endif + w.increments(); +} + +bool StepperCurrentScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + #if AXIS_IS_TMC(X) + case 2: UI_DECREMENT(AxisCurrent_mA, X ); break; + case 3: UI_INCREMENT(AxisCurrent_mA, X ); break; + #endif + #if AXIS_IS_TMC(X2) + case 4: UI_DECREMENT(AxisCurrent_mA, X2 ); break; + case 5: UI_INCREMENT(AxisCurrent_mA, X2 ); break; + #endif + #if AXIS_IS_TMC(Y) + case 6: UI_DECREMENT(AxisCurrent_mA, Y ); break; + case 7: UI_INCREMENT(AxisCurrent_mA, Y ); break; + #endif + #if AXIS_IS_TMC(Y2) + case 8: UI_DECREMENT(AxisCurrent_mA, Y2 ); break; + case 9: UI_INCREMENT(AxisCurrent_mA, Y2 ); break; + #endif + #if AXIS_IS_TMC(Z) + case 10: UI_DECREMENT(AxisCurrent_mA, Z ); break; + case 11: UI_INCREMENT(AxisCurrent_mA, Z ); break; + #endif + #if AXIS_IS_TMC(Z2) + case 12: UI_DECREMENT(AxisCurrent_mA, Z2 ); break; + case 13: UI_INCREMENT(AxisCurrent_mA, Z2 ); break; + #endif + #if AXIS_IS_TMC(E0) + case 14: UI_DECREMENT(AxisCurrent_mA, E0); break; + case 15: UI_INCREMENT(AxisCurrent_mA, E0); break; + #endif + #if AXIS_IS_TMC(E1) + case 16: UI_DECREMENT(AxisCurrent_mA, E1); break; + case 17: UI_INCREMENT(AxisCurrent_mA, E1); break; + #endif + #if AXIS_IS_TMC(E2) + case 18: UI_DECREMENT(AxisCurrent_mA, E2); break; + case 19: UI_INCREMENT(AxisCurrent_mA, E2); break; + #endif + #if AXIS_IS_TMC(E3) + case 20: UI_DECREMENT(AxisCurrent_mA, E3); break; + case 21: UI_INCREMENT(AxisCurrent_mA, E3); break; + #endif + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/steps_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/steps_screen.cpp new file mode 100644 index 0000000..e9bc50a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/steps_screen.cpp @@ -0,0 +1,86 @@ +/******************** + * steps_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void StepsScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(0); + w.units(GET_TEXT_F(MSG_UNITS_STEP_MM)); + w.heading( GET_TEXT_F(MSG_STEPS_PER_MM)); + w.color(x_axis) .adjuster( 2, GET_TEXT_F(MSG_AXIS_X), getAxisSteps_per_mm(X) ); + w.color(y_axis) .adjuster( 4, GET_TEXT_F(MSG_AXIS_Y), getAxisSteps_per_mm(Y) ); + w.color(z_axis) .adjuster( 6, GET_TEXT_F(MSG_AXIS_Z), getAxisSteps_per_mm(Z) ); + #if EXTRUDERS == 1 || DISABLED(DISTINCT_E_FACTORS) + w.color(e_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_E), getAxisSteps_per_mm(E0) ); + #elif HAS_MULTI_EXTRUDER + w.color(e_axis) .adjuster( 8, GET_TEXT_F(MSG_AXIS_E1), getAxisSteps_per_mm(E0) ); + w.color(e_axis) .adjuster(10, GET_TEXT_F(MSG_AXIS_E2), getAxisSteps_per_mm(E1) ); + #if EXTRUDERS > 2 + w.color(e_axis) .adjuster(12, GET_TEXT_F(MSG_AXIS_E3), getAxisSteps_per_mm(E2) ); + #endif + #if EXTRUDERS > 3 + w.color(e_axis) .adjuster(14, GET_TEXT_F(MSG_AXIS_E4), getAxisSteps_per_mm(E3) ); + #endif + #endif + w.increments(); +} + +bool StepsScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 2: UI_DECREMENT(AxisSteps_per_mm, X); break; + case 3: UI_INCREMENT(AxisSteps_per_mm, X); break; + case 4: UI_DECREMENT(AxisSteps_per_mm, Y); break; + case 5: UI_INCREMENT(AxisSteps_per_mm, Y); break; + case 6: UI_DECREMENT(AxisSteps_per_mm, Z); break; + case 7: UI_INCREMENT(AxisSteps_per_mm, Z); break; + case 8: UI_DECREMENT(AxisSteps_per_mm, E0); break; + case 9: UI_INCREMENT(AxisSteps_per_mm, E0); break; + #if HAS_MULTI_EXTRUDER + case 10: UI_DECREMENT(AxisSteps_per_mm, E1); break; + case 11: UI_INCREMENT(AxisSteps_per_mm, E1); break; + #endif + #if EXTRUDERS > 2 + case 12: UI_DECREMENT(AxisSteps_per_mm, E2); break; + case 13: UI_INCREMENT(AxisSteps_per_mm, E2); break; + #endif + #if EXTRUDERS > 3 + case 14: UI_DECREMENT(AxisSteps_per_mm, E3); break; + case 15: UI_INCREMENT(AxisSteps_per_mm, E3); break; + #endif + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp new file mode 100644 index 0000000..6c4aab6 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/stress_test_screen.cpp @@ -0,0 +1,149 @@ +/************************** + * stress_test_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU) + +#include "screens.h" +#include "screen_data.h" + +#define STRESS_TEST_CHANGE_INTERVAL 6000 + +#define GRID_COLS 4 +#define GRID_ROWS 9 + +using namespace FTDI; +using namespace Theme; +using namespace ExtUI; + +void StressTestScreen::drawDots(uint16_t x, uint16_t y, uint16_t w, uint16_t h) { + CommandProcessor cmd; + for (uint8_t i = 0; i < 100; i++) { + cmd.cmd(BEGIN(POINTS)) + .cmd(POINT_SIZE(20*16)) + .cmd(COLOR_RGB(random(0xFFFFFF))) + .cmd(VERTEX2F((x + random(w)) * 16,(y + random(h)) * 16)); + } +} + +bool StressTestScreen::watchDogTestNow() { + return screen_data.StressTest.next_watchdog_trigger && + ELAPSED(millis(), screen_data.StressTest.next_watchdog_trigger); +} + +void StressTestScreen::onRedraw(draw_mode_t) { + using namespace ExtUI; + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .font(font_medium) + .text(BTN_POS(1,1), BTN_SIZE(4,1), progmem_str(screen_data.StressTest.message)); + + drawDots(BTN_POS(1,3), BTN_SIZE(4,4)); + + cmd.font(font_medium).enabled(!watchDogTestNow()).colors(action_btn).tag(1).button(BTN_POS(2,8), BTN_SIZE(2,1), F("Exit")); +} + +bool StressTestScreen::onTouchEnd(uint8_t tag) { + CommandProcessor cmd; + switch (tag) { + case 1: + runTestOnBootup(false); + GOTO_SCREEN(StatusScreen); + break; + default: + return false; + } + return true; +} + +void StressTestScreen::runTestOnBootup(bool enable) { + // Use a magic value in passcode to indicate + // whether or not we need to re-run the test + // at startup. + LockScreen::set_hash(enable ? 0xDEAD : 0); + injectCommands_P(PSTR("M500")); +} + +void StressTestScreen::startupCheck() { + if (LockScreen::get_hash() == 0xDEAD) + GOTO_SCREEN(StressTestScreen); +} + +void StressTestScreen::onEntry() { + screen_data.StressTest.next_watchdog_trigger = millis() + 10000 + random(40000); + screen_data.StressTest.message = PSTR("Test 1: Stress testing..."); + + // Turn off heaters. + setTargetTemp_celsius(0, E0); + setTargetTemp_celsius(0, E1); + setTargetTemp_celsius(0, BED); + + runTestOnBootup(true); +} + +void StressTestScreen::recursiveLockup() { + screen_data.StressTest.message = PSTR("Test 2: Printer will restart."); + current_screen.onRefresh(); + recursiveLockup(); +} + +void StressTestScreen::iterativeLockup() { + screen_data.StressTest.message = PSTR("Test 3: Printer will restart."); + for (;;) current_screen.onRefresh(); +} + +void StressTestScreen::onIdle() { + current_screen.onRefresh(); + reset_menu_timeout(); + + if (!commandsInQueue()) { + if (!isPositionKnown()) { + injectCommands_P(G28_STR); + } + else { + injectCommands_P(PSTR( + "G0 X100 Y100 Z100 F6000\n" + "T0\nG4 S1" + TERN_(HAS_MULTI_EXTRUDER, "\nT1\nG4 S1") + "\nG0 X150 Y150 Z150" + )); + } + } + + if (refresh_timer.elapsed(STRESS_TEST_CHANGE_INTERVAL)) { + setTargetFan_percent(random(100),FAN0); + } + + if (watchDogTestNow()) { + if (random(2) % 2) + iterativeLockup(); + else + recursiveLockup(); + } + + BaseScreen::onIdle(); +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.cpp new file mode 100644 index 0000000..c3114a3 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.cpp @@ -0,0 +1,83 @@ +/********************* + * string_format.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +#define ROUND(val) uint16_t((val)+0.5) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wno-format" + +/** + * Formats a temperature string (e.g. "100°C") + */ +void format_temp(char *str, float t1) { + sprintf_P(str, PSTR("%3d" S_FMT), ROUND(t1), GET_TEXT(MSG_UNITS_C)); +} + +/** + * Formats a temperature string for an idle heater (e.g. "100 °C / idle") + */ +void format_temp_and_idle(char *str, float t1) { + sprintf_P(str, PSTR("%3d" S_FMT " / " S_FMT), ROUND(t1), GET_TEXT(MSG_UNITS_C), GET_TEXT(MSG_IDLE)); +} + +/** + * Formats a temperature string for an active heater (e.g. "100 / 200°C") + */ +void format_temp_and_temp(char *str, float t1, float t2) { + sprintf_P(str, PSTR("%3d / %3d" S_FMT), ROUND(t1), ROUND(t2), GET_TEXT(MSG_UNITS_C)); +} + +/** + * Formats a temperature string for a material (e.g. "100°C (PLA)") + */ +void format_temp_and_material(char *str, float t1, const char *material) { + sprintf_P(str, PSTR("%3d" S_FMT " (" S_FMT ")"), ROUND(t1), GET_TEXT(MSG_UNITS_C), material); +} + +/** + * Formats a position value (e.g. "10 mm") + */ +void format_position(char *str, float p, uint8_t decimals) { + dtostrf(p, 4 + decimals, decimals, str); + strcat_P(str, PSTR(" ")); + strcat_P(str, GET_TEXT(MSG_UNITS_MM)); +} + +/** + * Formats a position vector (e.g. "10; 20; 30 mm") + */ +void format_position(char *str, float x, float y, float z) { + char num1[7], num2[7], num3[7]; + dtostrf(x, 4, 2, num1); + dtostrf(y, 4, 2, num2); + dtostrf(z, 4, 2, num3); + sprintf_P(str, PSTR("%s; %s; %s " S_FMT), num1, num2, num3, GET_TEXT(MSG_UNITS_MM)); +} + +#pragma GCC diagnostic pop + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.h new file mode 100644 index 0000000..545c701 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/string_format.h @@ -0,0 +1,29 @@ +/******************* + * string_format.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +void format_temp(char *str, float t1); +void format_temp_and_idle(char *str, float t1); +void format_temp_and_temp(char *str, float t1, float t2); +void format_temp_and_material(char *str, float t1, const char *material); +void format_position(char *str, float p, uint8_t decimals = 1); +void format_position(char *str, float x, float y, float z); diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/temperature_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/temperature_screen.cpp new file mode 100644 index 0000000..bdd434b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/temperature_screen.cpp @@ -0,0 +1,119 @@ +/******************* + * boot_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; +using namespace ExtUI; + +void TemperatureScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + #if TOUCH_UI_LCD_TEMP_SCALING == 10 + w.precision(1, DEFAULT_MIDRANGE) + #else + w.precision(0, getTargetTemp_celsius(E0) == 0 ? DEFAULT_HIGHEST : DEFAULT_MIDRANGE) + #endif + .color(temp).units(GET_TEXT_F(MSG_UNITS_C)); + w.heading(GET_TEXT_F(MSG_TEMPERATURE)); + w.button(30, GET_TEXT_F(MSG_COOLDOWN)); + #ifndef NO_TOOLHEAD_HEATER_GCODE + #if ENABLED(TOUCH_UI_COCOA_PRESS) + w.adjuster( 2, GET_TEXT_F(MSG_NOZZLE), getTargetTemp_celsius(E0)); + w.adjuster( 4, GET_TEXT_F(MSG_BODY), getTargetTemp_celsius(E1)); + #if ENABLED(COCOA_PRESS_EXTRA_HEATER) + if (has_extra_heater()) + w.adjuster(6, GET_TEXT_F(MSG_EXTERNAL), getTargetTemp_celsius(E2)); + #endif + #elif HOTENDS == 1 + w.adjuster( 2, GET_TEXT_F(MSG_NOZZLE), getTargetTemp_celsius(E0)); + #else + w.adjuster( 2, F(LCD_STR_E0), getTargetTemp_celsius(E0)); + w.adjuster( 4, F(LCD_STR_E1), getTargetTemp_celsius(E1)); + #if HOTENDS > 2 + w.adjuster( 6, F(LCD_STR_E2), getTargetTemp_celsius(E2)); + #endif + #if HOTENDS > 3 + w.adjuster( 8, F(LCD_STR_E3), getTargetTemp_celsius(E3)); + #endif + #endif + #endif + #if HAS_HEATED_BED + w.adjuster( 20, GET_TEXT_F(MSG_BED), getTargetTemp_celsius(BED)); + #endif + #if HAS_HEATED_CHAMBER + w.adjuster( 22, GET_TEXT_F(MSG_CHAMBER), getTargetTemp_celsius(CHAMBER)); + #endif + #if HAS_FAN + w.color(fan_speed).units(GET_TEXT_F(MSG_UNITS_PERCENT)); + w.adjuster( 10, GET_TEXT_F(MSG_FAN_SPEED), getTargetFan_percent(FAN0)); + #endif + w.increments(); +} + +bool TemperatureScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 20: UI_DECREMENT(TargetTemp_celsius, BED); break; + case 21: UI_INCREMENT(TargetTemp_celsius, BED); break; + case 22: UI_DECREMENT(TargetTemp_celsius, CHAMBER); break; + case 23: UI_INCREMENT(TargetTemp_celsius, CHAMBER); break; + #ifndef NO_TOOLHEAD_HEATER_GCODE + case 2: UI_DECREMENT(TargetTemp_celsius, E0); break; + case 3: UI_INCREMENT(TargetTemp_celsius, E0); break; + #endif + #if HAS_MULTI_HOTEND + case 4: UI_DECREMENT(TargetTemp_celsius, E1); break; + case 5: UI_INCREMENT(TargetTemp_celsius, E1); break; + #endif + #if HOTENDS > 2 + case 6: UI_DECREMENT(TargetTemp_celsius, E2); break; + case 7: UI_INCREMENT(TargetTemp_celsius, E2); break; + #endif + #if HOTENDS > 3 + case 8: UI_DECREMENT(TargetTemp_celsius, E3); break; + case 9: UI_INCREMENT(TargetTemp_celsius, E3); break; + #endif + #if HAS_FAN + case 10: UI_DECREMENT(TargetFan_percent, FAN0); break; + case 11: UI_INCREMENT(TargetFan_percent, FAN0); break; + #endif + case 30: + #define _HOTEND_OFF(N) setTargetTemp_celsius(0, E##N); + REPEAT(HOTENDS, _HOTEND_OFF); + TERN_(HAS_HEATED_BED, setTargetTemp_celsius(0, BED)); + TERN_(HAS_HEATED_CHAMBER, setTargetTemp_celsius(0, CHAMBER)); + #if HAS_FAN + setTargetFan_percent(0, FAN0); + #endif + break; + default: + return false; + } + return true; +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_calibration_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_calibration_screen.cpp new file mode 100644 index 0000000..b5312ad --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_calibration_screen.cpp @@ -0,0 +1,94 @@ +/******************************** + * touch_calibration_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +#define GRID_COLS 4 +#define GRID_ROWS 16 + +#define TEXT_POS BTN_POS(1,1), BTN_SIZE(4,12) + +void TouchCalibrationScreen::onEntry() { + CommandProcessor cmd; + + BaseScreen::onEntry(); + + if (CLCD::is_touching()) { + // Ask the user to release the touch before starting, + // as otherwise the first calibration point could + // be misinterpreted. + cmd.cmd(CMD_DLSTART) + .cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)); + draw_text_box(cmd, TEXT_POS, GET_TEXT_F(MSG_TOUCH_CALIBRATION_START), OPT_CENTER, font_large); + cmd.cmd(DL::DL_DISPLAY) + .cmd(CMD_SWAP) + .execute(); + + while (CLCD::is_touching()) { + #if ENABLED(TOUCH_UI_DEBUG) + SERIAL_ECHO_MSG("Waiting for touch release"); + #endif + } + } + + // Force a refresh + cmd.cmd(CMD_DLSTART); + onRedraw(FOREGROUND); + cmd.cmd(DL::DL_DISPLAY); + cmd.execute(); +} + +void TouchCalibrationScreen::onRefresh() { + // Don't do the regular refresh, as this would + // cause the calibration be restarted on every + // touch. +} + +void TouchCalibrationScreen::onRedraw(draw_mode_t) { + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)); + + draw_text_box(cmd, TEXT_POS, GET_TEXT_F(MSG_TOUCH_CALIBRATION_PROMPT), OPT_CENTER, font_large); + cmd.cmd(CMD_CALIBRATE); +} + +void TouchCalibrationScreen::onIdle() { + if (!CLCD::is_touching() && !CommandProcessor::is_processing()) { + GOTO_PREVIOUS(); + #if ENABLED(TOUCH_UI_DEBUG) + SERIAL_ECHO_MSG("Calibration routine finished"); + #endif + } +} + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_registers_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_registers_screen.cpp new file mode 100644 index 0000000..3739413 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/touch_registers_screen.cpp @@ -0,0 +1,86 @@ +/****************************** + * touch_registers_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU) + +#include "screens.h" + +using namespace FTDI; +using namespace Theme; + +void TouchRegistersScreen::onRedraw(draw_mode_t) { + const uint32_t T_Transform_A = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_A); + const uint32_t T_Transform_B = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_B); + const uint32_t T_Transform_C = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_C); + const uint32_t T_Transform_D = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_D); + const uint32_t T_Transform_E = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_E); + const uint32_t T_Transform_F = CLCD::mem_read_32(CLCD::REG::TOUCH_TRANSFORM_F); + char b[20]; + + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .tag(0); + + #define GRID_ROWS 7 + #define GRID_COLS 2 + cmd.tag(0) + .font(font_xsmall) + .fgcolor(transformA) .button(BTN_POS(1,1), BTN_SIZE(1,1), F("TOUCH_XFORM_A")) + .fgcolor(transformB) .button(BTN_POS(1,2), BTN_SIZE(1,1), F("TOUCH_XFORM_B")) + .fgcolor(transformC) .button(BTN_POS(1,3), BTN_SIZE(1,1), F("TOUCH_XFORM_C")) + .fgcolor(transformD) .button(BTN_POS(1,4), BTN_SIZE(1,1), F("TOUCH_XFORM_D")) + .fgcolor(transformE) .button(BTN_POS(1,5), BTN_SIZE(1,1), F("TOUCH_XFORM_E")) + .fgcolor(transformF) .button(BTN_POS(1,6), BTN_SIZE(1,1), F("TOUCH_XFORM_F")) + + .fgcolor(transformVal).button(BTN_POS(2,1), BTN_SIZE(1,1), F(""), OPT_FLAT) + .fgcolor(transformVal).button(BTN_POS(2,2), BTN_SIZE(1,1), F(""), OPT_FLAT) + .fgcolor(transformVal).button(BTN_POS(2,3), BTN_SIZE(1,1), F(""), OPT_FLAT) + .fgcolor(transformVal).button(BTN_POS(2,4), BTN_SIZE(1,1), F(""), OPT_FLAT) + .fgcolor(transformVal).button(BTN_POS(2,5), BTN_SIZE(1,1), F(""), OPT_FLAT) + .fgcolor(transformVal).button(BTN_POS(2,6), BTN_SIZE(1,1), F(""), OPT_FLAT); + + sprintf_P(b, PSTR("0x%08lX"), T_Transform_A); cmd.text( BTN_POS(2,1), BTN_SIZE(1,1), b); + sprintf_P(b, PSTR("0x%08lX"), T_Transform_B); cmd.text( BTN_POS(2,2), BTN_SIZE(1,1), b); + sprintf_P(b, PSTR("0x%08lX"), T_Transform_C); cmd.text( BTN_POS(2,3), BTN_SIZE(1,1), b); + sprintf_P(b, PSTR("0x%08lX"), T_Transform_D); cmd.text( BTN_POS(2,4), BTN_SIZE(1,1), b); + sprintf_P(b, PSTR("0x%08lX"), T_Transform_E); cmd.text( BTN_POS(2,5), BTN_SIZE(1,1), b); + sprintf_P(b, PSTR("0x%08lX"), T_Transform_F); cmd.text( BTN_POS(2,6), BTN_SIZE(1,1), b); + + cmd.colors(action_btn).font(font_medium) + .tag(1).button(BTN_POS(2,7), BTN_SIZE(1,1), F("Back")); + #undef GRID_COLS + #undef GRID_ROWS + } + + bool TouchRegistersScreen::onTouchEnd(uint8_t tag) { + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + default: + return false; + } + return true; + } + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/tune_menu.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/tune_menu.cpp new file mode 100644 index 0000000..5a29010 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/tune_menu.cpp @@ -0,0 +1,156 @@ +/******************* + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) && DISABLED(TOUCH_UI_LULZBOT_BIO) + +#include "screens.h" + +#include "../../../../../feature/host_actions.h" + +using namespace FTDI; +using namespace Theme; + +void TuneMenu::onRedraw(draw_mode_t what) { + if (what & BACKGROUND) { + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)); + } + + #if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_ROWS 9 + #define GRID_COLS 2 + #define TEMPERATURE_POS BTN_POS(1,1), BTN_SIZE(2,1) + #define FIL_CHANGE_POS BTN_POS(1,2), BTN_SIZE(2,1) + #define FILAMENT_POS BTN_POS(1,3), BTN_SIZE(2,1) + #define NUDGE_NOZ_POS BTN_POS(1,4), BTN_SIZE(2,1) + #define SPEED_POS BTN_POS(1,5), BTN_SIZE(2,1) + #define PAUSE_POS BTN_POS(1,6), BTN_SIZE(2,1) + #define STOP_POS BTN_POS(1,7), BTN_SIZE(2,1) + #define CASE_LIGHT_POS BTN_POS(1,8), BTN_SIZE(2,1) + #define ADVANCED_SETTINGS_POS BTN_POS(1,9), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(2,9), BTN_SIZE(1,1) + #else + #define GRID_ROWS 5 + #define GRID_COLS 2 + #define TEMPERATURE_POS BTN_POS(1,1), BTN_SIZE(1,1) + #define NUDGE_NOZ_POS BTN_POS(2,1), BTN_SIZE(1,1) + #define FIL_CHANGE_POS BTN_POS(1,2), BTN_SIZE(1,1) + #define SPEED_POS BTN_POS(2,2), BTN_SIZE(1,1) + #define PAUSE_POS BTN_POS(1,3), BTN_SIZE(1,1) + #define STOP_POS BTN_POS(2,3), BTN_SIZE(1,1) + #define FILAMENT_POS BTN_POS(1,4), BTN_SIZE(1,1) + #define CASE_LIGHT_POS BTN_POS(2,4), BTN_SIZE(1,1) + #define ADVANCED_SETTINGS_POS BTN_POS(1,5), BTN_SIZE(1,1) + #define BACK_POS BTN_POS(2,5), BTN_SIZE(2,1) + #endif + + if (what & FOREGROUND) { + const bool sdOrHostPrinting = ExtUI::isPrinting(); + const bool sdOrHostPaused = ExtUI::isPrintingPaused(); + + CommandProcessor cmd; + cmd.colors(normal_btn) + .font(font_medium) + .tag(2).button(TEMPERATURE_POS, GET_TEXT_F(MSG_TEMPERATURE)) + .enabled(!sdOrHostPrinting || sdOrHostPaused) + .tag(3).button(FIL_CHANGE_POS, GET_TEXT_F(MSG_FILAMENTCHANGE)) + .enabled(EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR)) + .tag(9).button(FILAMENT_POS, GET_TEXT_F(MSG_FILAMENT)) + .enabled(BOTH(HAS_LEVELING, HAS_BED_PROBE) || ENABLED(BABYSTEPPING)) + .tag(4).button(NUDGE_NOZ_POS, GET_TEXT_F(TERN(BABYSTEPPING, MSG_NUDGE_NOZZLE, MSG_ZPROBE_ZOFFSET))) + .tag(5).button(SPEED_POS, GET_TEXT_F(MSG_PRINT_SPEED)) + .enabled(sdOrHostPrinting) + .tag(sdOrHostPaused ? 7 : 6) + .button(PAUSE_POS, sdOrHostPaused ? GET_TEXT_F(MSG_RESUME_PRINT) : GET_TEXT_F(MSG_PAUSE_PRINT)) + .enabled(sdOrHostPrinting) + .tag(8).button(STOP_POS, GET_TEXT_F(MSG_STOP_PRINT)) + .enabled(ENABLED(CASE_LIGHT_ENABLE)) + .tag(10).button(CASE_LIGHT_POS, GET_TEXT_F(MSG_CASE_LIGHT)) + .tag(11).button(ADVANCED_SETTINGS_POS, GET_TEXT_F(MSG_ADVANCED_SETTINGS)) + .tag(1).colors(action_btn) + .button(BACK_POS, GET_TEXT_F(MSG_BACK)); + } + #undef GRID_COLS + #undef GRID_ROWS +} + +bool TuneMenu::onTouchEnd(uint8_t tag) { + using namespace Theme; + using namespace ExtUI; + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + case 2: GOTO_SCREEN(TemperatureScreen); break; + case 3: GOTO_SCREEN(ChangeFilamentScreen); break; + case 4: + #if ENABLED(BABYSTEPPING) + GOTO_SCREEN(NudgeNozzleScreen); + #elif BOTH(HAS_LEVELING, HAS_BED_PROBE) + GOTO_SCREEN(ZOffsetScreen); + #endif + break; + case 5: GOTO_SCREEN(FeedratePercentScreen); break; + case 6: pausePrint(); break; + case 7: resumePrint(); break; + case 8: + GOTO_SCREEN(ConfirmAbortPrintDialogBox); + current_screen.forget(); + PUSH_SCREEN(StatusScreen); + break; + #if EITHER(LIN_ADVANCE, FILAMENT_RUNOUT_SENSOR) + case 9: GOTO_SCREEN(FilamentMenu); break; + #endif + #if ENABLED(CASE_LIGHT_ENABLE) + case 10: GOTO_SCREEN(CaseLightScreen); break; + #endif + case 11: GOTO_SCREEN(AdvancedSettingsMenu); break; + default: + return false; + } + return true; +} + +void TuneMenu::pausePrint() { + sound.play(twinkle, PLAY_ASYNCHRONOUS); + if (ExtUI::isPrintingFromMedia()) + ExtUI::pausePrint(); + #ifdef ACTION_ON_PAUSE + else host_action_pause(); + #endif + GOTO_SCREEN(StatusScreen); +} + +void TuneMenu::resumePrint() { + sound.play(twinkle, PLAY_ASYNCHRONOUS); + if (ExtUI::awaitingUserConfirm()) + ExtUI::setUserConfirmed(); + else if (ExtUI::isPrintingFromMedia()) + ExtUI::resumePrint(); + #ifdef ACTION_ON_RESUME + else host_action_resume(); + #endif + GOTO_SCREEN(StatusScreen); +} + +#endif // TOUCH_UI_FTDI_EVE && !TOUCH_UI_LULZBOT_BIO diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/widget_demo_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/widget_demo_screen.cpp new file mode 100644 index 0000000..9688710 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/widget_demo_screen.cpp @@ -0,0 +1,158 @@ +/************************** + * widget_demo_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if BOTH(TOUCH_UI_FTDI_EVE, TOUCH_UI_DEVELOPER_MENU) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +uint16_t slider_val; +bool show_grid; + +void WidgetsScreen::onEntry() { + BaseScreen::onEntry(); + CLCD::turn_on_backlight(); + SoundPlayer::set_volume(255); +} + +void WidgetsScreen::onRedraw(draw_mode_t) { + using namespace ExtUI; + CommandProcessor cmd; + cmd.cmd(CLEAR_COLOR_RGB(bg_color)) + .cmd(CLEAR(true,true,true)) + .cmd(COLOR_RGB(bg_text_enabled)) + .tag(0); + + const uint16_t hrs = (slider_val*12/0xFFFFU); + const uint16_t m = (slider_val*12*60/0xFFFFU)%60; + const uint16_t s = (slider_val*12*60*60/0xFFFFU)%60; + + #if ENABLED(TOUCH_UI_PORTRAIT) + #define GRID_COLS 3 + #define GRID_ROWS 8 + cmd.font(font_large) + .cmd(COLOR_RGB(bg_text_enabled)) + .text (BTN_POS(1,1), BTN_SIZE(3,1), F("Sample Widgets")) + .tag(0).text (BTN_POS(2,6), BTN_SIZE(1,1), F("Show grid:")) + .colors(ui_toggle) + .tag(2).dial (BTN_POS(1,2), BTN_SIZE(1,2), slider_val) + .tag(0).clock (BTN_POS(1,4), BTN_SIZE(1,2), hrs, m, s, 0) + .gauge (BTN_POS(1,6), BTN_SIZE(1,2), 5, 4, slider_val, 0xFFFFU) + .font(font_medium) + .colors(ui_slider) + .tag(4).slider (BTN_POS(2,3), BTN_SIZE(2,1), slider_val, 0xFFFFU) + .tag(5).progress (BTN_POS(2,4), BTN_SIZE(2,1), slider_val, 0xFFFFU) + .tag(6).scrollbar (BTN_POS(2,5), BTN_SIZE(2,1), slider_val, 1000, 0xFFFFU) + .font(font_small) + .colors(ui_toggle) + .tag(7).toggle (BTN_POS(3,6), BTN_SIZE(1,1), F("no\xFFyes"), show_grid) + .colors(normal_btn) + .font(font_medium) + .tag(1) + .button (BTN_POS(2, 8), BTN_SIZE(1,1), F("1")) + .button (BTN_POS(3, 8), BTN_SIZE(1,1), F("2")) + .colors(action_btn) + .button (BTN_POS(1, 8), BTN_SIZE(1,1), F("Back")); + #else + #define GRID_COLS 4 + #define GRID_ROWS 8 + + cmd.font(font_large) + .text (BTN_POS(1,1), BTN_SIZE(4,1), F("Sample Widgets")) + .tag(0).text (BTN_POS(3,6), BTN_SIZE(1,1), F("Show grid:")) + .colors(ui_toggle) + .tag(2).dial (BTN_POS(1,2), BTN_SIZE(1,3), slider_val) + .tag(3).dial (BTN_POS(1,5), BTN_SIZE(1,3), slider_val) + .tag(0).clock (BTN_POS(2,2), BTN_SIZE(1,3), hrs, m, s, 0) + .gauge (BTN_POS(2,5), BTN_SIZE(1,3), 5, 4, slider_val, 0xFFFFU) + .font(font_medium) + .colors(ui_slider) + .tag(4).slider (BTN_POS(3,3), BTN_SIZE(2,1), slider_val, 0xFFFFU) + .tag(5).progress (BTN_POS(3,4), BTN_SIZE(2,1), slider_val, 0xFFFFU) + .tag(6).scrollbar (BTN_POS(3,5), BTN_SIZE(2,1), slider_val, 1000, 0xFFFFU) + .font(font_small) + .colors(ui_toggle) + .tag(7).toggle (BTN_POS(4,6), BTN_SIZE(1,1), F("no\xFFyes"), show_grid) + .colors(normal_btn) + .font(font_medium) + .tag(1).button (BTN_POS(3, 8), BTN_SIZE(1,1), F("1")) + .button (BTN_POS(4, 8), BTN_SIZE(1,1), F("2")) + .colors(action_btn) + .button (BTN_POS(1, 8), BTN_SIZE(2,1), F("Back")); + #endif + + cmd.cmd(COLOR_RGB(bg_text_enabled)); + if (show_grid) DRAW_LAYOUT_GRID +} + +bool WidgetsScreen::onTouchStart(uint8_t tag) { + CommandProcessor cmd; + switch (tag) { + case 1: GOTO_PREVIOUS(); break; + #if ENABLED(TOUCH_UI_PORTRAIT) + case 2: cmd.track_circular (BTN_POS(1,2), BTN_SIZE(1,2), 2).execute(); break; + case 4: cmd.track_linear (BTN_POS(2,3), BTN_SIZE(2,1), 4).execute(); break; + case 5: cmd.track_linear (BTN_POS(2,4), BTN_SIZE(2,1), 5).execute(); break; + case 6: cmd.track_linear (BTN_POS(2,5), BTN_SIZE(2,1), 6).execute(); break; + #else + case 2: cmd.track_circular (BTN_POS(1,2), BTN_SIZE(1,3), 2).execute(); break; + case 3: cmd.track_circular (BTN_POS(1,5), BTN_SIZE(1,3), 3).execute(); break; + case 4: cmd.track_linear (BTN_POS(3,3), BTN_SIZE(2,1), 4).execute(); break; + case 5: cmd.track_linear (BTN_POS(3,4), BTN_SIZE(2,1), 5).execute(); break; + case 6: cmd.track_linear (BTN_POS(3,5), BTN_SIZE(2,1), 6).execute(); break; + #endif + case 7: show_grid = !show_grid; break; + default: + return false; + } + + return true; +} + +void WidgetsScreen::onIdle() { + if (refresh_timer.elapsed(TOUCH_UPDATE_INTERVAL)) { + refresh_timer.start(); + + uint16_t value; + CommandProcessor cmd; + switch (cmd.track_tag(value)) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + slider_val = value; break; + default: + return; + } + onRefresh(); + } + BaseScreen::onIdle(); +} + +#endif // TOUCH_UI_FTDI_EVE && TOUCH_UI_DEVELOPER_MENU diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/z_offset_screen.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/z_offset_screen.cpp new file mode 100644 index 0000000..0acfbb0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/screens/z_offset_screen.cpp @@ -0,0 +1,54 @@ +/*********************** + * z_offset_screen.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../config.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) && BOTH(HAS_LEVELING, HAS_BED_PROBE) + +#include "screens.h" + +using namespace FTDI; +using namespace ExtUI; +using namespace Theme; + +void ZOffsetScreen::onRedraw(draw_mode_t what) { + widgets_t w(what); + w.precision(2, BaseNumericAdjustmentScreen::DEFAULT_MIDRANGE).units(GET_TEXT_F(MSG_UNITS_MM)); + + w.heading( GET_TEXT_F(MSG_ZPROBE_ZOFFSET)); + w.color(z_axis).adjuster(4, GET_TEXT_F(MSG_ZPROBE_ZOFFSET), getZOffset_mm()); + w.increments(); +} + +bool ZOffsetScreen::onTouchHeld(uint8_t tag) { + const float increment = getIncrement(); + switch (tag) { + case 4: UI_DECREMENT(ZOffset_mm); break; + case 5: UI_INCREMENT(ZOffset_mm); break; + default: + return false; + } + SaveSettingsDialogBox::settingsChanged(); + return true; +} + +#endif // TOUCH_UI_FTDI_EVE && HAS_BED_PROBE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bitmaps.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bitmaps.h new file mode 100644 index 0000000..8c0366e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bitmaps.h @@ -0,0 +1,183 @@ +/************* + * bitmaps.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +namespace Theme { + using namespace FTDI; + + constexpr PROGMEM bitmap_info_t Extruder_Icon_Info = { + .format = L1, + .linestride = 3, + .filter = BILINEAR, + .wrapx = BORDER, + .wrapy = BORDER, + .RAMG_offset = 8000, + .width = 24, + .height = 23, + }; + + constexpr PROGMEM unsigned char Extruder_Icon[] = { + 0x3F, 0xFF, 0xFC, + 0x7F, 0xFF, 0xFE, + 0xC0, 0x00, 0x03, + 0xC0, 0x00, 0x03, + 0xC0, 0x00, 0x03, + 0xC0, 0x00, 0x03, + 0x7F, 0xFF, 0xFE, + 0x3F, 0xFF, 0xFC, + 0x3F, 0xFF, 0xFC, + 0x7F, 0xFF, 0xFE, + 0xC0, 0x00, 0x03, + 0xC0, 0x00, 0x03, + 0xC0, 0x00, 0x03, + 0xC0, 0x00, 0x03, + 0x7F, 0xFF, 0xFE, + 0x7F, 0xFF, 0xFE, + 0x07, 0xFF, 0xE0, + 0x03, 0xFF, 0xC0, + 0x01, 0x81, 0x80, + 0x00, 0xC3, 0x00, + 0x00, 0x66, 0x00, + 0x00, 0x3C, 0x00, + 0x00, 0x3C, 0x00 + }; + + constexpr PROGMEM bitmap_info_t Bed_Heat_Icon_Info = { + .format = L1, + .linestride = 4, + .filter = BILINEAR, + .wrapx = BORDER, + .wrapy = BORDER, + .RAMG_offset = 8100, + .width = 32, + .height = 23, + }; + + constexpr PROGMEM unsigned char Bed_Heat_Icon[] = { + 0x01, 0x81, 0x81, 0x80, + 0x01, 0x81, 0x81, 0x80, + 0x00, 0xC0, 0xC0, 0xC0, + 0x00, 0xC0, 0xC0, 0xC0, + 0x00, 0x60, 0x60, 0x60, + 0x00, 0x60, 0x60, 0x60, + 0x00, 0xC0, 0xC0, 0xC0, + 0x00, 0xC0, 0xC0, 0xC0, + 0x01, 0x81, 0x81, 0x80, + 0x01, 0x81, 0x81, 0x80, + 0x03, 0x03, 0x03, 0x00, + 0x03, 0x03, 0x03, 0x00, + 0x06, 0x06, 0x06, 0x00, + 0x06, 0x06, 0x06, 0x00, + 0x03, 0x03, 0x03, 0x00, + 0x03, 0x03, 0x03, 0x00, + 0x01, 0x81, 0x81, 0x80, + 0x01, 0x81, 0x81, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xC0, 0x00, 0x00, 0x03, + 0xFF, 0xFF, 0xFF, 0xFF + }; + + constexpr PROGMEM bitmap_info_t Fan_Icon_Info = { + .format = L1, + .linestride = 4, + .filter = BILINEAR, + .wrapx = BORDER, + .wrapy = BORDER, + .RAMG_offset = 8300, + .width = 32, + .height = 32, + }; + + constexpr PROGMEM unsigned char Fan_Icon[] = { + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xF8, 0x00, 0x00, 0x1F, + 0xF0, 0x03, 0xF8, 0x0F, + 0xE0, 0x07, 0xF0, 0x07, + 0xC0, 0x0F, 0xE0, 0x03, + 0xC0, 0x1F, 0xE0, 0x03, + 0xC0, 0x1F, 0xE0, 0x03, + 0xC0, 0x0F, 0xE0, 0x03, + 0xC0, 0x07, 0xE0, 0x03, + 0xC0, 0x03, 0xC0, 0x03, + 0xD0, 0x00, 0x00, 0xC3, + 0xD8, 0x03, 0xC1, 0xE3, + 0xDF, 0xC7, 0xE3, 0xF3, + 0xDF, 0xEF, 0xF7, 0xFB, + 0xDF, 0xEF, 0xF7, 0xFB, + 0xDF, 0xEF, 0xF7, 0xFB, + 0xDF, 0xEF, 0xF7, 0xFB, + 0xCF, 0xC7, 0xE3, 0xFB, + 0xC7, 0x83, 0xC0, 0x1B, + 0xC3, 0x00, 0x00, 0x0B, + 0xC0, 0x03, 0xC0, 0x03, + 0xC0, 0x07, 0xE0, 0x03, + 0xC0, 0x07, 0xF0, 0x03, + 0xC0, 0x07, 0xF8, 0x03, + 0xC0, 0x07, 0xF8, 0x03, + 0xC0, 0x07, 0xF0, 0x03, + 0xE0, 0x0F, 0xE0, 0x07, + 0xF0, 0x1F, 0xC0, 0x0F, + 0xF8, 0x00, 0x00, 0x1F, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF + }; + + constexpr PROGMEM bitmap_info_t TD_Icon_Info = { + .format = L1, + .linestride = 7, + .filter = BILINEAR, + .wrapx = BORDER, + .wrapy = BORDER, + .RAMG_offset = 9000, + .width = 50, + .height = 20, + }; + + constexpr PROGMEM unsigned char TD_Icon[] = { + 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00, // Thumb Drive Widget + 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x80, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x80, + 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, + 0x00, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x00 + }; + + constexpr PROGMEM uint32_t UTF8_FONT_OFFSET = 10000; +}; // namespace Theme diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bootscreen_logo_portrait.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bootscreen_logo_portrait.h new file mode 100644 index 0000000..5d97358 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/bootscreen_logo_portrait.h @@ -0,0 +1,42 @@ +/**************************************************************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/** + * This file was auto-generated using "svg2cpp.pl" + * + * 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, x_max = 272.000000, + y_min = 0.000000, y_max = 480.000000; + +const PROGMEM uint16_t logo_green[] = {0x8048, 0x46D9, 0x27BC, 0x9DBA, 0xD8D3, 0x9DBA}; +const PROGMEM uint16_t logo_mark[] = {0xDB9F, 0xAC0C, 0xDA6F, 0xAC2D, 0xD970, 0xAC91, 0xD8C0, 0xAD23, 0xD885, 0xADCF, 0xD8C0, 0xAE7A, 0xD970, 0xAF0C, 0xDA6F, 0xAF6F, 0xDB9F, 0xAF8F, 0xDCCE, 0xAF6F, 0xDDD0, 0xAF0C, 0xDE7D, 0xAE7B, 0xDEB9, 0xADCF, 0xDE7D, 0xAD22, 0xDDD0, 0xAC91, 0xDCCE, 0xAC2D, 0xFFFF, 0xDB9F, 0xABC3, 0xDCFE, 0xABEA, 0xDE28, 0xAC5E, 0xDEF1, 0xAD06, 0xDF36, 0xADCF, 0xDEF1, 0xAE95, 0xDE28, 0xAF3E, 0xDCFE, 0xAFB1, 0xDB9F, 0xAFD8, 0xDA3F, 0xAFB1, 0xD916, 0xAF3E, 0xD849, 0xAE95, 0xD808, 0xADCF, 0xD849, 0xAD06, 0xD916, 0xAC5E, 0xDA3F, 0xABEA, 0xFFFF, 0xDB7D, 0xACE6, 0xDAE4, 0xACE6, 0xDAE4, 0xADA9, 0xDB7D, 0xADA9, 0xDC3B, 0xAD94, 0xDC71, 0xAD48, 0xDC3B, 0xACFD, 0xFFFF, 0xDB85, 0xAC9E, 0xDCCB, 0xACC8, 0xDD37, 0xAD47, 0xDCF6, 0xADAC, 0xDC3E, 0xADDE, 0xDC85, 0xADFF, 0xDCE8, 0xAE4E, 0xDD92, 0xAEEA, 0xDCBD, 0xAEEA, 0xDC1E, 0xAE58, 0xDBA7, 0xAE03, 0xDB36, 0xADEF, 0xDAE4, 0xADEF, 0xDAE4, 0xAEEA, 0xDA26, 0xAEEA, 0xDA26, 0xAC9E}; +const PROGMEM uint16_t logo_type[] = {0xD8D5, 0xA520, 0xD8A5, 0xA563, 0xD82E, 0xA57F, 0xD348, 0xA57F, 0xD2D1, 0xA598, 0xD2A0, 0xA5D9, 0xD2A0, 0xAF7A, 0xD274, 0xAFBE, 0xD202, 0xAFDA, 0xCD37, 0xAFDA, 0xCCBF, 0xAFBE, 0xCC8F, 0xAF7A, 0xCC8F, 0xA5D9, 0xCC63, 0xA598, 0xCBF1, 0xA57F, 0xC70B, 0xA57F, 0xC694, 0xA563, 0xC664, 0xA520, 0xC664, 0xA28C, 0xC70B, 0xA22C, 0xD82E, 0xA22C, 0xD8A5, 0xA248, 0xD8D5, 0xA28C, 0xFFFF, 0xB138, 0xAC8C, 0xB952, 0xAC8C, 0xB952, 0xA57F, 0xB138, 0xA57F, 0xFFFF, 0xBF27, 0xA421, 0xBF57, 0xA476, 0xBF6D, 0xA4D0, 0xBF6D, 0xAD36, 0xBF57, 0xAD90, 0xBF27, 0xADE6, 0xBBFA, 0xAFB2, 0xBB60, 0xAFCF, 0xBABD, 0xAFDA, 0xAFCE, 0xAFDA, 0xAF30, 0xAFCF, 0xAE9A, 0xAFB2, 0xAB6E, 0xADE6, 0xAB39, 0xAD90, 0xAB28, 0xAD36, 0xAB28, 0xA4D0, 0xAB39, 0xA476, 0xAB6E, 0xA421, 0xAE9A, 0xA255, 0xAF30, 0xA239, 0xAFCE, 0xA22C, 0xBABD, 0xA22C, 0xBB60, 0xA239, 0xBBFA, 0xA255, 0xFFFF, 0x93A4, 0xACDC, 0x9CEA, 0xACDC, 0x9CEA, 0xAA34, 0x93A4, 0xAA34, 0x93A4, 0xACDC, 0xFFFF, 0x93A4, 0xA796, 0x9CEA, 0xA796, 0x9CEA, 0xA525, 0x93A4, 0xA525, 0xFFFF, 0xA227, 0xA421, 0xA258, 0xA478, 0xA26E, 0xA4D5, 0xA26E, 0xA700, 0xA24F, 0xA757, 0xA204, 0xA7A5, 0xA089, 0xA8B8, 0xA061, 0xA903, 0xA092, 0xA949, 0xA1FC, 0xAA43, 0xA24B, 0xAA91, 0xA26E, 0xAAE8, 0xA26E, 0xAD36, 0xA258, 0xAD90, 0xA227, 0xADE6, 0x9EFC, 0xAFB2, 0x9E61, 0xAFCF, 0x9DBE, 0xAFDA, 0x8ED0, 0xAFDA, 0x8E28, 0xAF7A, 0x8E28, 0xA28C, 0x8E59, 0xA248, 0x8ED0, 0xA22C, 0x9DBE, 0xA22C, 0x9E61, 0xA239, 0x9EFC, 0xA255, 0xFFFF, 0x853C, 0xA502, 0x8517, 0xA557, 0x84C9, 0xA5A2, 0x7994, 0xACC8, 0x8494, 0xACC8, 0x850A, 0xACE4, 0x853C, 0xAD27, 0x853C, 0xAF7A, 0x850A, 0xAFBE, 0x8494, 0xAFDA, 0x7371, 0xAFDA, 0x72C9, 0xAF7A, 0x72C9, 0xAD09, 0x72E8, 0xACB2, 0x7333, 0xAC64, 0x7EA5, 0xA53E, 0x73A6, 0xA53E, 0x732F, 0xA522, 0x72FE, 0xA4DF, 0x72FE, 0xA28C, 0x732F, 0xA248, 0x73A6, 0xA22C, 0x8494, 0xA22C, 0x850A, 0xA248, 0x853C, 0xA28C, 0xFFFF, 0x6B68, 0xAC87, 0x6BDB, 0xACA3, 0x6C07, 0xACE6, 0x6C07, 0xAF7A, 0x6BDB, 0xAFBE, 0x6B68, 0xAFDA, 0x5C84, 0xAFDA, 0x5BDC, 0xAF7A, 0x5BDC, 0xA28C, 0x5C84, 0xA22C, 0x6146, 0xA22C, 0x61EE, 0xA28C, 0x61EE, 0xAC2D, 0x621E, 0xAC6E, 0x6295, 0xAC87, 0xFFFF, 0x52C6, 0xA248, 0x52F7, 0xA28C, 0x52F7, 0xAD45, 0x52EE, 0xAD45, 0x52DC, 0xAD9B, 0x52B1, 0xADE6, 0x4F85, 0xAFB2, 0x4EEA, 0xAFCF, 0x4E47, 0xAFDA, 0x4359, 0xAFDA, 0x42BA, 0xAFCF, 0x4224, 0xAFB2, 0x3EF8, 0xADE6, 0x3EC3, 0xAD90, 0x3EB2, 0xAD36, 0x3EB2, 0xA28C, 0x3EE2, 0xA248, 0x3F5A, 0xA22C, 0x441B, 0xA22C, 0x4493, 0xA248, 0x44C3, 0xA28C, 0x44C3, 0xAC2D, 0x44F4, 0xAC71, 0x456B, 0xAC8C, 0x4C3E, 0xAC8C, 0x4CB1, 0xAC71, 0x4CDD, 0xAC2D, 0x4CDD, 0xA28C, 0x4D0D, 0xA248, 0x4D85, 0xA22C, 0x524F, 0xA22C, 0xFFFF, 0x3748, 0xAC87, 0x37BB, 0xACA3, 0x37E7, 0xACE6, 0x37E7, 0xAF7A, 0x37BB, 0xAFBE, 0x3748, 0xAFDA, 0x2864, 0xAFDA, 0x27BC, 0xAF7A, 0x27BC, 0xA28C, 0x2864, 0xA22C, 0x2D26, 0xA22C, 0x2DCD, 0xA28C, 0x2DCD, 0xAC2D, 0x2DFE, 0xAC6E, 0x2E75, 0xAC87}; +const PROGMEM uint16_t logo_black[] = {0x8048, 0x527A, 0x8ADE, 0x5CDE, 0x75B2, 0x5CDE, 0xFFFF, 0x8048, 0x4FF6, 0x71D9, 0x5E20, 0x8EB8, 0x5E20, 0x8048, 0x4FF6, 0xFFFF, 0x4436, 0x8D8E, 0x4ECC, 0x97F2, 0x39A0, 0x97F2, 0xFFFF, 0x4436, 0x8B0A, 0x35C8, 0x9934, 0x52A5, 0x9934, 0xFFFF, 0xBC3D, 0x8D8E, 0xC6D4, 0x97F2, 0xB1A7, 0x97F2, 0xFFFF, 0xBC3D, 0x8B0A, 0xADCE, 0x9934, 0xCAAC, 0x9934, 0xFFFF, 0x8045, 0x6778, 0x7F6D, 0x67A7, 0x7E9D, 0x689F, 0x7D49, 0x69EA, 0x7B41, 0x6A81, 0x7908, 0x6A3A, 0x7726, 0x692C, 0x75EA, 0x685A, 0x7505, 0x684C, 0x744A, 0x6899, 0x73F5, 0x69A8, 0x7345, 0x6B1A, 0x7193, 0x6BF8, 0x6F4D, 0x6C08, 0x6CFA, 0x6B45, 0x6B61, 0x6AA3, 0x6A7D, 0x6AB7, 0x69EB, 0x6B1D, 0x6A1D, 0x6C34, 0x6A22, 0x6DB8, 0x68E5, 0x6ECD, 0x66B9, 0x6F33, 0x6417, 0x6EC5, 0x6239, 0x6E5C, 0x6165, 0x6E91, 0x6108, 0x6F09, 0x61C1, 0x7018, 0x6282, 0x7196, 0x61CF, 0x72D1, 0x5FE5, 0x7384, 0x5D38, 0x7380, 0x5B4B, 0x7365, 0x5A97, 0x73B7, 0x5A74, 0x7438, 0x5B90, 0x7520, 0x5CE8, 0x7671, 0x5CCB, 0x77BB, 0x5B43, 0x78B0, 0x58B6, 0x7914, 0x56D7, 0x7944, 0x564F, 0x79AD, 0x5667, 0x7A2F, 0x57DA, 0x7AE3, 0x59B7, 0x7BF3, 0x5A31, 0x7D37, 0x5927, 0x7E5D, 0x56E0, 0x7F1E, 0x5529, 0x7F93, 0x54D7, 0x800D, 0x5529, 0x8087, 0x56E0, 0x80FD, 0x5926, 0x81BE, 0x5A30, 0x82E5, 0x59B5, 0x8428, 0x57D8, 0x8538, 0x5664, 0x85EB, 0x564C, 0x866D, 0x56D4, 0x86D7, 0x58B2, 0x8708, 0x5B3F, 0x876B, 0x5CC6, 0x8860, 0x5CE3, 0x89AA, 0x5B8B, 0x8AFC, 0x5A6D, 0x8BE3, 0x5A91, 0x8C65, 0x5B44, 0x8CB7, 0x5D32, 0x8C9C, 0x5FDE, 0x8C98, 0x61C7, 0x8D4B, 0x627A, 0x8E87, 0x61B9, 0x9005, 0x60FF, 0x9114, 0x615C, 0x918B, 0x622F, 0x91C0, 0x640E, 0x9158, 0x66B0, 0x90EA, 0x68DC, 0x9150, 0x6A18, 0x9266, 0x6A12, 0x93E9, 0x69E0, 0x9501, 0x6A72, 0x9567, 0x6B56, 0x957B, 0x6CEE, 0x94D9, 0x6F43, 0x9417, 0x7188, 0x9428, 0x7339, 0x9506, 0x73E9, 0x9678, 0x743E, 0x9787, 0x74F8, 0x97D4, 0x75DD, 0x97C6, 0x771A, 0x96F4, 0x78FB, 0x95E6, 0x7B35, 0x95A1, 0x7D3D, 0x9637, 0x7E91, 0x9782, 0x7F60, 0x987A, 0x8038, 0x98AA, 0x810F, 0x987B, 0x81DF, 0x9782, 0x8333, 0x9638, 0x853B, 0x95A1, 0x8775, 0x95E7, 0x8956, 0x96F5, 0x8A92, 0x97C8, 0x8B78, 0x97D6, 0x8C32, 0x9789, 0x8C88, 0x967A, 0x8D37, 0x9508, 0x8EE9, 0x942A, 0x912F, 0x941A, 0x9383, 0x94DD, 0x951B, 0x957F, 0x95FF, 0x956B, 0x9690, 0x9505, 0x9660, 0x93ED, 0x9659, 0x926A, 0x9797, 0x9154, 0x99C3, 0x90EF, 0x9C65, 0x915D, 0x9E43, 0x91C6, 0x9F17, 0x9191, 0x9F74, 0x9119, 0x9EBB, 0x900A, 0x9DFA, 0x8E8C, 0x9EAE, 0x8D51, 0xA098, 0x8C9E, 0xA345, 0x8CA2, 0xA531, 0x8CBE, 0xA5E5, 0x8C6B, 0xA609, 0x8BEA, 0xA4EC, 0x8B02, 0xA394, 0x89B1, 0xA3B2, 0x8867, 0xA53A, 0x8772, 0xA7C6, 0x870E, 0xA9A5, 0x86DE, 0xAA2D, 0x8675, 0xAA14, 0x85F2, 0xA8A2, 0x853F, 0xA6C5, 0x842E, 0xA64B, 0x82EB, 0xA755, 0x81C5, 0xA99C, 0x8104, 0xAB52, 0x808F, 0xABA6, 0x8015, 0xAB52, 0x7F9B, 0xA99C, 0x7F25, 0xA755, 0x7E64, 0xA64C, 0x7D3E, 0xA6C7, 0x7BFA, 0xA8A5, 0x7AEA, 0xAA18, 0x7A37, 0xAA31, 0x79B5, 0xA9A9, 0x794B, 0xA7CA, 0x791B, 0xA53C, 0x78B7, 0xA3B6, 0x77C1, 0xA39A, 0x7677, 0xA4F1, 0x7526, 0xA60E, 0x743F, 0xA5EB, 0x73BD, 0xA538, 0x736B, 0xA34B, 0x7387, 0xA09E, 0x738A, 0x9EB4, 0x72D6, 0x9E02, 0x719B, 0x9EC4, 0x701D, 0x9F7E, 0x6F0E, 0x9F20, 0x6E96, 0x9E4E, 0x6E61, 0x9C6E, 0x6ECA, 0x99CB, 0x6F37, 0x97A0, 0x6ED2, 0x9664, 0x6DBC, 0x966B, 0x6C38, 0x969B, 0x6B21, 0x960B, 0x6ABB, 0x9526, 0x6AA6, 0x938E, 0x6B48, 0x913B, 0x6C0B, 0x8EF4, 0x6BFA, 0x8D43, 0x6B1D, 0x8C94, 0x69AA, 0x8C3F, 0x689B, 0x8B85, 0x684D, 0x8A9E, 0x685C, 0x8962, 0x692E, 0x8781, 0x6A3C, 0x8546, 0x6A82, 0x833F, 0x69EA, 0x81EC, 0x68A0, 0x811C, 0x67A8, 0x8045, 0x6778, 0x8045, 0x6778, 0xFFFF, 0x8047, 0x6AA0, 0x81C8, 0x6AFA, 0x8268, 0x6BD5, 0x81C8, 0x6CAF, 0x8047, 0x6D09, 0x7EC6, 0x6CAF, 0x7E27, 0x6BD5, 0x7EC6, 0x6AFA, 0x8047, 0x6AA0, 0x8047, 0x6AA0, 0xFFFF, 0x803E, 0x6E19, 0x867C, 0x6E71, 0x8C65, 0x6F75, 0x91D7, 0x711B, 0x96AD, 0x735B, 0x9ABC, 0x762C, 0x9DA2, 0x794C, 0x9F5F, 0x7CA2, 0x9FF3, 0x8011, 0x9F5E, 0x8380, 0x9DA1, 0x86D5, 0x9ABA, 0x89F6, 0x96AB, 0x8CC7, 0x91D6, 0x8F08, 0x8C65, 0x90AD, 0x867C, 0x91B1, 0x803D, 0x9209, 0x7A00, 0x91B1, 0x7416, 0x90AD, 0x6EA6, 0x8F08, 0x69D0, 0x8CC7, 0x65D6, 0x8A0A, 0x62EE, 0x86F4, 0x6125, 0x839B, 0x6089, 0x8011, 0x6124, 0x7C88, 0x62ED, 0x792E, 0x65D6, 0x7619, 0x69CF, 0x735B, 0x6EA5, 0x711B, 0x7416, 0x6F75, 0x7A00, 0x6E71, 0x803E, 0x6E19, 0x803E, 0x6E19, 0xFFFF, 0x803E, 0x6EB2, 0x7A5A, 0x6F04, 0x74B2, 0x6FF8, 0x6F4B, 0x7194, 0x6A8F, 0x73C7, 0x66A2, 0x7681, 0x63D5, 0x7986, 0x6226, 0x7CBF, 0x6197, 0x8011, 0x6226, 0x8363, 0x63D5, 0x869C, 0x66A2, 0x89A2, 0x6A8F, 0x8C5B, 0x6F4B, 0x8E8E, 0x74B2, 0x902B, 0x7A5A, 0x911E, 0x803D, 0x9170, 0x803E, 0x9170, 0x8621, 0x911E, 0x8BCA, 0x902B, 0x9130, 0x8E8E, 0x95ED, 0x8C5B, 0x99CF, 0x89AB, 0x9CA7, 0x869C, 0x9E55, 0x8367, 0x9EE5, 0x8011, 0x9E55, 0x7CBB, 0x9CA7, 0x7986, 0x99CF, 0x7677, 0x95ED, 0x73C7, 0x9130, 0x7194, 0x8BCA, 0x6FF8, 0x8621, 0x6F04, 0x803E, 0x6EB2, 0x803E, 0x6EB2, 0xFFFF, 0x80BC, 0x6FD7, 0x80AF, 0x71D8, 0x7FC8, 0x71D9, 0x7FB7, 0x6FD8, 0x80BC, 0x6FD7, 0x80BC, 0x6FD7, 0xFFFF, 0x83CB, 0x6FF6, 0x84CD, 0x700B, 0x843E, 0x7206, 0x835B, 0x71F4, 0xFFFF, 0x7CA9, 0x6FF8, 0x7D1A, 0x71F5, 0x7C37, 0x7207, 0x7BA7, 0x700D, 0x7CA9, 0x6FF8, 0x7CA9, 0x6FF8, 0xFFFF, 0x87CD, 0x7068, 0x88C7, 0x7092, 0x87BA, 0x727C, 0x86DF, 0x7258, 0xFFFF, 0x78A8, 0x706B, 0x7997, 0x725A, 0x78BA, 0x727E, 0x77AD, 0x7095, 0x78A8, 0x706B, 0x78A8, 0x706B, 0xFFFF, 0x6700, 0x708A, 0x6880, 0x70E5, 0x6920, 0x71BF, 0x6880, 0x7299, 0x66FF, 0x72F4, 0x657F, 0x7299, 0x64E0, 0x71BF, 0x657F, 0x70E4, 0x6700, 0x708A, 0x6700, 0x708A, 0xFFFF, 0x998D, 0x708C, 0x9B0E, 0x70E6, 0x9BAE, 0x71C0, 0x9B0E, 0x729B, 0x998D, 0x72F6, 0x980D, 0x729B, 0x976E, 0x71C1, 0x980D, 0x70E7, 0x998D, 0x708C, 0x998D, 0x708C, 0xFFFF, 0x8BA7, 0x712C, 0x8C95, 0x716A, 0x8B10, 0x7339, 0x8A3F, 0x7303, 0x8BA7, 0x712C, 0xFFFF, 0x74CE, 0x712F, 0x7635, 0x7307, 0x7564, 0x733C, 0x73DE, 0x716D, 0x74CE, 0x712F, 0x74CE, 0x712F, 0xFFFF, 0x8F47, 0x723F, 0x9023, 0x728E, 0x8E2D, 0x743A, 0x8D6B, 0x73F4, 0x8F47, 0x723F, 0xFFFF, 0x712D, 0x7242, 0x7308, 0x73F7, 0x7248, 0x743D, 0x7050, 0x7292, 0x712D, 0x7242, 0x712D, 0x7242, 0xFFFF, 0x803E, 0x72F6, 0x891B, 0x73F4, 0x909A, 0x76CC, 0x959F, 0x7B0B, 0x975E, 0x8011, 0x959F, 0x8517, 0x909A, 0x8957, 0x891B, 0x8C2E, 0x803E, 0x8D2B, 0x7761, 0x8C2E, 0x6FE2, 0x8957, 0x6ADD, 0x8517, 0x691E, 0x8011, 0x6ADD, 0x7B0B, 0x6FE2, 0x76CC, 0x7761, 0x73F4, 0x803E, 0x72F6, 0x803E, 0x72F6, 0xFFFF, 0x803E, 0x738F, 0x77C8, 0x7481, 0x70A0, 0x7738, 0x6BD7, 0x7B46, 0x6A2C, 0x8011, 0x6BD7, 0x84DC, 0x70A1, 0x88EA, 0x77C9, 0x8BA1, 0x803E, 0x8C93, 0x88B4, 0x8BA1, 0x8FDB, 0x88EA, 0x94A5, 0x84DD, 0x9650, 0x8011, 0x94A5, 0x7B46, 0x8FDB, 0x7738, 0x88B4, 0x7481, 0x803E, 0x738F, 0x803E, 0x738F, 0xFFFF, 0x929B, 0x739A, 0x935C, 0x73FA, 0x9100, 0x7578, 0x905A, 0x7527, 0x9175, 0x745E, 0xFFFF, 0x6DDC, 0x739D, 0x7022, 0x7527, 0x6F74, 0x757C, 0x6D16, 0x73FF, 0x6DDC, 0x739D, 0x6DDC, 0x739D, 0xFFFF, 0x9589, 0x7533, 0x9634, 0x75A4, 0x937E, 0x76ED, 0x92E8, 0x768B, 0xFFFF, 0x6AEB, 0x7539, 0x6D8D, 0x7690, 0x6CFB, 0x76F0, 0x6CEC, 0x76FA, 0x6BED, 0x7674, 0x6A40, 0x75A9, 0x6A45, 0x75A7, 0x6AEB, 0x7539, 0x6AEB, 0x7539, 0xFFFF, 0x980B, 0x7707, 0x989A, 0x7784, 0x9597, 0x7892, 0x951A, 0x7825, 0xFFFF, 0x686A, 0x770C, 0x6B5B, 0x782A, 0x6ADF, 0x7897, 0x67DD, 0x7788, 0x686A, 0x770C, 0x686A, 0x770C, 0xFFFF, 0x9A12, 0x790A, 0x9A7E, 0x7991, 0x9740, 0x7A5E, 0x96E1, 0x79E8, 0x9A12, 0x790A, 0xFFFF, 0x6664, 0x790F, 0x6996, 0x79ED, 0x6937, 0x7A63, 0x65F9, 0x7996, 0x6664, 0x790F, 0x6664, 0x790F, 0xFFFF, 0x9B91, 0x7B32, 0x9BDB, 0x7BC1, 0x9870, 0x7C48, 0x9831, 0x7BCB, 0xFFFF, 0x64E6, 0x7B37, 0x6847, 0x7BD0, 0x6807, 0x7C4C, 0x649D, 0x7BC5, 0x64E6, 0x7B37, 0x64E6, 0x7B37, 0xFFFF, 0x9C82, 0x7D72, 0x9CA7, 0x7E06, 0x9925, 0x7E46, 0x9903, 0x7DC5, 0xFFFF, 0x63F7, 0x7D78, 0x6776, 0x7DC9, 0x6756, 0x7E49, 0x63D3, 0x7E0A, 0x63F7, 0x7D78, 0x63F7, 0x7D78, 0xFFFF, 0x5C87, 0x7EDB, 0x5E08, 0x7F35, 0x5EA8, 0x800F, 0x5E08, 0x80E9, 0x5C87, 0x8144, 0x5C85, 0x8144, 0x5B06, 0x80E9, 0x5A67, 0x800F, 0x5B06, 0x7F35, 0x5C87, 0x7EDB, 0x5C87, 0x7EDB, 0xFFFF, 0xA402, 0x7EDE, 0xA583, 0x7F38, 0xA623, 0x8011, 0xA623, 0x8013, 0xA583, 0x80EC, 0xA402, 0x8147, 0xA281, 0x80ED, 0xA1E2, 0x8013, 0xA281, 0x7F38, 0xA402, 0x7EDE, 0xA402, 0x7EDE, 0xFFFF, 0x9CE0, 0x7FC0, 0x9CE0, 0x8055, 0x9957, 0x804D, 0x9957, 0x7FCB, 0xFFFF, 0x639D, 0x7FC5, 0x6726, 0x7FCE, 0x6726, 0x8051, 0x639D, 0x805A, 0x639D, 0x7FC5, 0x639D, 0x7FC5, 0xFFFF, 0x9927, 0x81D1, 0x9CAA, 0x8210, 0x9C87, 0x82A2, 0x9907, 0x8252, 0x9927, 0x81D1, 0x9927, 0x81D1, 0xFFFF, 0x6757, 0x81D5, 0x6777, 0x8255, 0x63F9, 0x82A7, 0x63D4, 0x8214, 0xFFFF, 0x9877, 0x83CF, 0x9BE2, 0x8455, 0x9B99, 0x84E3, 0x9838, 0x844C, 0x9877, 0x83CF, 0x9877, 0x83CF, 0xFFFF, 0x6808, 0x83D3, 0x6848, 0x8450, 0x64E7, 0x84E8, 0x649E, 0x845A, 0xFFFF, 0x9749, 0x85B9, 0x9A88, 0x8684, 0x9A1D, 0x870C, 0x96EB, 0x862E, 0x9749, 0x85B9, 0x9749, 0x85B9, 0xFFFF, 0x6938, 0x85BD, 0x6997, 0x8634, 0x6665, 0x8710, 0x65F9, 0x8689, 0xFFFF, 0x95A2, 0x8785, 0x98A5, 0x8892, 0x9818, 0x890F, 0x9527, 0x87F2, 0x95A2, 0x8785, 0x95A2, 0x8785, 0xFFFF, 0x6ADF, 0x878A, 0x6B5B, 0x87F8, 0x686A, 0x8914, 0x67DC, 0x8897, 0x6ADF, 0x878A, 0xFFFF, 0x6CF7, 0x892F, 0x6D8D, 0x8991, 0x6AEB, 0x8AE9, 0x6A40, 0x8A79, 0xFFFF, 0x9380, 0x8932, 0x9645, 0x8A72, 0x963E, 0x8A77, 0x9599, 0x8AE3, 0x92F5, 0x898D, 0x9380, 0x8932, 0x9380, 0x8932, 0xFFFF, 0x9110, 0x8AA1, 0x936F, 0x8C1F, 0x92AA, 0x8C80, 0x9064, 0x8AF7, 0x9110, 0x8AA1, 0x9110, 0x8AA1, 0xFFFF, 0x6F73, 0x8AA5, 0x7021, 0x8AFB, 0x7035, 0x8B04, 0x6DED, 0x8C8B, 0x6DE1, 0x8C87, 0x6D17, 0x8C23, 0xFFFF, 0x8E3E, 0x8BE1, 0x9037, 0x8D8B, 0x8F59, 0x8DDC, 0x8D7C, 0x8C27, 0x8E3E, 0x8BE1, 0x8E3E, 0x8BE1, 0xFFFF, 0x7259, 0x8BEB, 0x731B, 0x8C31, 0x7140, 0x8DE7, 0x7064, 0x8D97, 0xFFFF, 0x8B21, 0x8CE3, 0x8CA9, 0x8EB2, 0x8BBA, 0x8EEF, 0x8A51, 0x8D18, 0x8B21, 0x8CE3, 0x8B21, 0x8CE3, 0xFFFF, 0x7576, 0x8CEB, 0x7648, 0x8D20, 0x74E0, 0x8EF8, 0x73F2, 0x8EBB, 0xFFFF, 0x66F3, 0x8D2F, 0x6874, 0x8D8A, 0x687D, 0x8D8F, 0x6886, 0x8D94, 0x6926, 0x8E6E, 0x6887, 0x8F48, 0x6705, 0x8FA2, 0x6584, 0x8F49, 0x657F, 0x8F45, 0x6570, 0x8F3E, 0x6573, 0x8F3E, 0x64D3, 0x8E63, 0x6573, 0x8D89, 0x66F3, 0x8D2F, 0x66F3, 0x8D2F, 0xFFFF, 0x9993, 0x8D31, 0x9B13, 0x8D8C, 0x9BB4, 0x8E66, 0x9B16, 0x8F40, 0x9993, 0x8F9A, 0x9814, 0x8F40, 0x9774, 0x8E66, 0x9812, 0x8D8C, 0x9993, 0x8D31, 0x9993, 0x8D31, 0xFFFF, 0x87CD, 0x8DA1, 0x88DC, 0x8F8B, 0x87E0, 0x8FB5, 0x86F0, 0x8DC6, 0x87CD, 0x8DA1, 0x87CD, 0x8DA1, 0xFFFF, 0x78CD, 0x8DA8, 0x79A8, 0x8DCB, 0x78BC, 0x8FBB, 0x77C1, 0x8F92, 0xFFFF, 0x8450, 0x8E19, 0x84E2, 0x9014, 0x83E0, 0x9029, 0x836C, 0x8E2C, 0x8450, 0x8E19, 0x8450, 0x8E19, 0xFFFF, 0x7C48, 0x8E1C, 0x7D2B, 0x8E2E, 0x7CBD, 0x902C, 0x7BBB, 0x9017, 0x7C48, 0x8E1C, 0xFFFF, 0x80BF, 0x8E49, 0x80D2, 0x904A, 0x7FCC, 0x904A, 0x7FD9, 0x8E49, 0x80BF, 0x8E49, 0x80BF, 0x8E49, 0xFFFF, 0x804F, 0x9321, 0x81D0, 0x937A, 0x8271, 0x9455, 0x81D1, 0x952F, 0x8051, 0x958A, 0x7ECF, 0x9530, 0x7E2F, 0x9456, 0x7ECE, 0x937B, 0x804F, 0x9321, 0x804F, 0x9321, 0xFFFF, 0x8048, 0x46D9, 0x27BC, 0x9DBA, 0xD8D3, 0x9DBA, 0xFFFF, 0x8048, 0x4BC9, 0x952E, 0x604A, 0x6B62, 0x604A, 0xFFFF, 0x68D2, 0x62CE, 0x97BF, 0x62CE, 0xB9BA, 0x8427, 0xA239, 0x9B36, 0x5E16, 0x9B36, 0x46B6, 0x8446, 0x68D2, 0x62CE, 0xFFFF, 0xBC3E, 0x869F, 0xD13B, 0x9B36, 0xA742, 0x9B36, 0xFFFF, 0x4431, 0x86BE, 0x590E, 0x9B36, 0x2F54, 0x9B36, 0x4431, 0x86BE}; +const PROGMEM uint16_t logo_white[] = {0x80BC, 0x6FD7, 0x80AF, 0x71D8, 0x7FC8, 0x71D9, 0x7FB7, 0x6FD8, 0x80BC, 0x6FD7, 0xFFFF, 0x83CB, 0x6FF6, 0x84CD, 0x700B, 0x843E, 0x7206, 0x835B, 0x71F4, 0xFFFF, 0x7CA9, 0x6FF8, 0x7D1A, 0x71F5, 0x7C37, 0x7207, 0x7BA7, 0x700D, 0x7CA9, 0x6FF8, 0x7CA9, 0x6FF8, 0xFFFF, 0x87CD, 0x7068, 0x88C7, 0x7092, 0x87BA, 0x727C, 0x86DF, 0x7258, 0xFFFF, 0x78A8, 0x706B, 0x7997, 0x725A, 0x78BA, 0x727E, 0x77AD, 0x7095, 0x78A8, 0x706B, 0x78A8, 0x706B, 0xFFFF, 0x8BA7, 0x712C, 0x8C95, 0x716A, 0x8B10, 0x7339, 0x8A3F, 0x7303, 0xFFFF, 0x74CE, 0x712F, 0x7635, 0x7307, 0x7564, 0x733C, 0x73DE, 0x716D, 0x74CE, 0x712F, 0x74CE, 0x712F, 0xFFFF, 0x8F47, 0x723F, 0x9023, 0x728E, 0x8E2D, 0x743A, 0x8D6B, 0x73F4, 0xFFFF, 0x712D, 0x7242, 0x7309, 0x73F7, 0x7248, 0x743D, 0x7050, 0x7292, 0x712D, 0x7242, 0x712D, 0x7242, 0xFFFF, 0x929B, 0x739A, 0x935C, 0x73FA, 0x9100, 0x7578, 0x905A, 0x7527, 0xFFFF, 0x6DDC, 0x739D, 0x7022, 0x7527, 0x6F74, 0x757C, 0x6D16, 0x73FF, 0x6DDC, 0x739D, 0x6DDC, 0x739D, 0xFFFF, 0x9589, 0x7533, 0x9634, 0x75A4, 0x937E, 0x76ED, 0x92E8, 0x768B, 0xFFFF, 0x6AEB, 0x7539, 0x6D8D, 0x7690, 0x6CFB, 0x76F0, 0x6A40, 0x75A9, 0x6AEB, 0x7539, 0xFFFF, 0x980B, 0x7707, 0x989A, 0x7784, 0x9597, 0x7892, 0x951A, 0x7825, 0xFFFF, 0x686A, 0x770C, 0x6B5B, 0x782A, 0x6ADF, 0x7897, 0x67DD, 0x7788, 0x686A, 0x770C, 0x686A, 0x770C, 0xFFFF, 0x9A12, 0x790A, 0x9A7E, 0x7991, 0x9740, 0x7A5E, 0x96E1, 0x79E8, 0xFFFF, 0x6664, 0x790F, 0x6996, 0x79ED, 0x6937, 0x7A63, 0x65F9, 0x7996, 0x6664, 0x790F, 0x6664, 0x790F, 0xFFFF, 0x9B91, 0x7B32, 0x9BDB, 0x7BC1, 0x9870, 0x7C48, 0x9831, 0x7BCC, 0xFFFF, 0x64E6, 0x7B37, 0x6847, 0x7BD0, 0x6807, 0x7C4C, 0x649D, 0x7BC5, 0x64E6, 0x7B37, 0x64E6, 0x7B37, 0xFFFF, 0x9C82, 0x7D72, 0x9CA7, 0x7E06, 0x9925, 0x7E46, 0x9903, 0x7DC5, 0xFFFF, 0x63F7, 0x7D78, 0x6776, 0x7DC9, 0x6756, 0x7E49, 0x63D3, 0x7E0A, 0x63F7, 0x7D78, 0x63F7, 0x7D78, 0xFFFF, 0x9CE0, 0x7FC0, 0x9CE0, 0x8055, 0x9957, 0x804D, 0x9957, 0x7FCB, 0xFFFF, 0x639D, 0x7FC5, 0x6726, 0x7FCE, 0x6726, 0x8051, 0x639D, 0x805A, 0x639D, 0x7FC5, 0xFFFF, 0x9927, 0x81D1, 0x9CAA, 0x8210, 0x9C87, 0x82A2, 0x9907, 0x8252, 0x9927, 0x81D1, 0x9927, 0x81D1, 0xFFFF, 0x6757, 0x81D5, 0x6777, 0x8256, 0x63F9, 0x82A7, 0x63D4, 0x8214, 0xFFFF, 0x9877, 0x83CF, 0x9BE2, 0x8455, 0x9B99, 0x84E3, 0x9838, 0x844C, 0x9877, 0x83CF, 0xFFFF, 0x6808, 0x83D3, 0x6848, 0x8450, 0x64E7, 0x84E8, 0x649E, 0x845A, 0xFFFF, 0x9749, 0x85B9, 0x9A88, 0x8684, 0x9A1D, 0x870C, 0x96EB, 0x862E, 0x9749, 0x85B9, 0x9749, 0x85B9, 0xFFFF, 0x6938, 0x85BD, 0x6997, 0x8634, 0x6665, 0x8710, 0x65F9, 0x8689, 0xFFFF, 0x95A2, 0x8785, 0x98A5, 0x8892, 0x9818, 0x890F, 0x9527, 0x87F2, 0x95A2, 0x8785, 0x95A2, 0x8785, 0xFFFF, 0x6ADF, 0x878A, 0x6B5B, 0x87F8, 0x686A, 0x8915, 0x67DC, 0x8897, 0xFFFF, 0x6CF7, 0x8930, 0x6D8D, 0x8991, 0x6AEB, 0x8AE9, 0x6A40, 0x8A79, 0xFFFF, 0x9380, 0x8932, 0x9645, 0x8A72, 0x9599, 0x8AE3, 0x92F5, 0x898D, 0x9380, 0x8932, 0xFFFF, 0x9110, 0x8AA1, 0x936F, 0x8C1F, 0x92AA, 0x8C80, 0x9064, 0x8AF7, 0x9110, 0x8AA1, 0x9110, 0x8AA1, 0xFFFF, 0x6F73, 0x8AA5, 0x7021, 0x8AFB, 0x6DED, 0x8C8C, 0x6D17, 0x8C23, 0xFFFF, 0x8E3E, 0x8BE1, 0x9037, 0x8D8B, 0x8F59, 0x8DDC, 0x8D7C, 0x8C27, 0x8E3E, 0x8BE1, 0x8E3E, 0x8BE1, 0xFFFF, 0x7259, 0x8BEB, 0x731B, 0x8C31, 0x7140, 0x8DE7, 0x7064, 0x8D97, 0xFFFF, 0x8B21, 0x8CE3, 0x8CA9, 0x8EB2, 0x8BBA, 0x8EEF, 0x8A51, 0x8D18, 0x8B21, 0x8CE3, 0x8B21, 0x8CE3, 0xFFFF, 0x7576, 0x8CEB, 0x7648, 0x8D20, 0x74E0, 0x8EF8, 0x73F2, 0x8EBB, 0xFFFF, 0x87CD, 0x8DA1, 0x88DC, 0x8F8B, 0x87E0, 0x8FB5, 0x86F0, 0x8DC6, 0x87CD, 0x8DA1, 0x87CD, 0x8DA1, 0xFFFF, 0x78CC, 0x8DA8, 0x79A8, 0x8DCB, 0x78BC, 0x8FBB, 0x77C0, 0x8F92, 0xFFFF, 0x8450, 0x8E19, 0x84E2, 0x9014, 0x83E0, 0x9029, 0x836C, 0x8E2C, 0x8450, 0x8E19, 0x8450, 0x8E19, 0xFFFF, 0x7C48, 0x8E1C, 0x7D2B, 0x8E2E, 0x7CBD, 0x902C, 0x7BBB, 0x9017, 0xFFFF, 0x80BE, 0x8E49, 0x80D1, 0x904A, 0x7FCC, 0x904A, 0x7FD9, 0x8E49, 0x80BE, 0x8E49, 0xFFFF, 0x8276, 0x75D6, 0x83AF, 0x75FE, 0x8436, 0x7628, 0x84AE, 0x7661, 0x8542, 0x7706, 0x8512, 0x77BA, 0x8457, 0x7845, 0x8335, 0x788B, 0x8318, 0x7882, 0x82D8, 0x7860, 0x831E, 0x7830, 0x8353, 0x7823, 0x83E6, 0x77F9, 0x8464, 0x7790, 0x847A, 0x771A, 0x8415, 0x76B7, 0x83B6, 0x7691, 0x8351, 0x7676, 0x827F, 0x7662, 0x81BB, 0x7687, 0x8161, 0x76AF, 0x8123, 0x76DA, 0x80E5, 0x771A, 0x80C5, 0x774D, 0x80B8, 0x77C1, 0x80D1, 0x77EE, 0x8107, 0x7814, 0x81CC, 0x786B, 0x837F, 0x7918, 0x8464, 0x7983, 0x84C0, 0x79B2, 0x852D, 0x79FD, 0x859D, 0x7ABC, 0x858E, 0x7B79, 0x8545, 0x7C25, 0x84D9, 0x7CC5, 0x8469, 0x7D4D, 0x843B, 0x7DCD, 0x8555, 0x7DA8, 0x85D3, 0x7D67, 0x870D, 0x7CA0, 0x87E0, 0x7BC0, 0x880D, 0x7B5B, 0x886D, 0x7A46, 0x88B3, 0x799B, 0x88CC, 0x7970, 0x893A, 0x78EA, 0x8995, 0x78A8, 0x8A01, 0x786F, 0x8AF8, 0x781F, 0x8BA6, 0x77FD, 0x8C0C, 0x77EF, 0x8C96, 0x77FB, 0x8D1D, 0x7815, 0x8D59, 0x7826, 0x8E40, 0x7889, 0x8EDB, 0x7925, 0x8EFC, 0x797B, 0x8EFF, 0x79D4, 0x8E71, 0x7A7B, 0x8D58, 0x7AD2, 0x8C23, 0x7ADE, 0x8AFF, 0x7A97, 0x8AF5, 0x7A81, 0x8AEF, 0x7A4E, 0x8B68, 0x7A52, 0x8B96, 0x7A5F, 0x8C39, 0x7A87, 0x8D33, 0x7A7F, 0x8E07, 0x7A3F, 0x8E66, 0x79CB, 0x8E63, 0x7985, 0x8E43, 0x793F, 0x8DC6, 0x78C6, 0x8CFA, 0x7876, 0x8C7E, 0x785F, 0x8C18, 0x7857, 0x8B84, 0x7874, 0x8B22, 0x788F, 0x8A7D, 0x78CA, 0x8A2E, 0x78F9, 0x89F0, 0x7930, 0x89A3, 0x79A5, 0x8979, 0x7AC0, 0x897C, 0x7B9C, 0x8972, 0x7BF2, 0x88CC, 0x7D32, 0x87B7, 0x7E4C, 0x8665, 0x7F52, 0x8660, 0x7F5A, 0x878F, 0x7F01, 0x88AE, 0x7EC2, 0x89FD, 0x7E9E, 0x8B8D, 0x7EC6, 0x8C40, 0x7F0E, 0x8CB6, 0x7F68, 0x8D1D, 0x7FD7, 0x8DFA, 0x80BD, 0x8EA8, 0x816E, 0x8F34, 0x81D4, 0x8F8A, 0x81F9, 0x8FDA, 0x820A, 0x90AB, 0x820F, 0x9120, 0x81FF, 0x91A5, 0x81DC, 0x91F4, 0x81B8, 0x922C, 0x8198, 0x9288, 0x812B, 0x927D, 0x80AB, 0x9252, 0x8068, 0x921C, 0x8033, 0x9174, 0x7FEB, 0x9099, 0x7FEB, 0x8FCF, 0x8029, 0x8F5D, 0x808D, 0x8F47, 0x80A4, 0x8ED4, 0x80A4, 0x8EC5, 0x8070, 0x8F65, 0x7FE6, 0x906D, 0x7F92, 0x91A4, 0x7F90, 0x92A8, 0x7FF7, 0x92FC, 0x8043, 0x9331, 0x8090, 0x9349, 0x813D, 0x92D1, 0x81E3, 0x9264, 0x8227, 0x91E5, 0x825B, 0x915D, 0x8280, 0x90D3, 0x8296, 0x8FA0, 0x829A, 0x8F2C, 0x8286, 0x8EE7, 0x8273, 0x8E78, 0x824A, 0x8DA9, 0x81D4, 0x8CB9, 0x8127, 0x8B68, 0x802C, 0x8B22, 0x8001, 0x8AC3, 0x7FE7, 0x8A50, 0x7FF4, 0x88FD, 0x8068, 0x87A4, 0x811D, 0x879E, 0x812D, 0x8904, 0x81F1, 0x89D4, 0x8285, 0x8A7C, 0x8343, 0x8A94, 0x8431, 0x8A4E, 0x84A1, 0x89E8, 0x850E, 0x892F, 0x85E5, 0x88B0, 0x86E5, 0x88C0, 0x8757, 0x88F2, 0x878D, 0x8927, 0x87AD, 0x8ABF, 0x8821, 0x8B0E, 0x881E, 0x8B70, 0x8811, 0x8C1B, 0x87D6, 0x8C9B, 0x8776, 0x8CC4, 0x873D, 0x8CD3, 0x8705, 0x8CA2, 0x86A3, 0x8C06, 0x8662, 0x8B39, 0x864F, 0x8A77, 0x8662, 0x89F9, 0x864D, 0x8A10, 0x8606, 0x8A66, 0x85F7, 0x8B35, 0x85DC, 0x8C50, 0x85FD, 0x8D3C, 0x8663, 0x8D94, 0x870A, 0x8D7D, 0x875F, 0x8D3A, 0x87B8, 0x8CB1, 0x882D, 0x8BC1, 0x888C, 0x8B30, 0x88A7, 0x8A8D, 0x88AE, 0x89EE, 0x8898, 0x896E, 0x887E, 0x8869, 0x882D, 0x87EE, 0x87EA, 0x87A4, 0x87A8, 0x878E, 0x8785, 0x874D, 0x86E3, 0x875D, 0x8637, 0x87FD, 0x8466, 0x8705, 0x835A, 0x86B8, 0x8359, 0x84A4, 0x8358, 0x7F20, 0x851B, 0x7F13, 0x864D, 0x8016, 0x86F9, 0x818E, 0x87D8, 0x823B, 0x8869, 0x8272, 0x88C9, 0x8276, 0x8915, 0x8266, 0x893D, 0x81FB, 0x89D8, 0x8197, 0x8A21, 0x8119, 0x8A62, 0x80A7, 0x8A8A, 0x8016, 0x8AAA, 0x7EDC, 0x8AAE, 0x7DC5, 0x8A63, 0x7D55, 0x8A29, 0x7CFA, 0x89E5, 0x7CAD, 0x8939, 0x7D1B, 0x8895, 0x7E00, 0x8825, 0x7F27, 0x8800, 0x7F66, 0x880F, 0x7F69, 0x8850, 0x7E49, 0x8873, 0x7D9A, 0x88C9, 0x7D4F, 0x893E, 0x7D8B, 0x89B2, 0x7DD8, 0x89E6, 0x7E36, 0x8A10, 0x7F02, 0x8A40, 0x7FDB, 0x8A34, 0x8046, 0x8A16, 0x8091, 0x89F5, 0x80A5, 0x89EB, 0x80FE, 0x89AB, 0x8126, 0x8981, 0x8159, 0x8918, 0x814F, 0x88E6, 0x8128, 0x88B8, 0x8094, 0x8856, 0x7EFC, 0x8796, 0x7D74, 0x86E7, 0x7D3D, 0x86C5, 0x7CD8, 0x8674, 0x7C98, 0x8605, 0x7CA0, 0x8536, 0x7D7C, 0x83E6, 0x7E07, 0x8357, 0x7DED, 0x835B, 0x79CC, 0x843E, 0x7962, 0x8448, 0x77CB, 0x8450, 0x76F3, 0x8438, 0x763E, 0x841E, 0x7502, 0x83FE, 0x746C, 0x83FD, 0x73E4, 0x840A, 0x72CE, 0x8444, 0x729B, 0x8457, 0x71E6, 0x84B7, 0x71B5, 0x84EB, 0x719B, 0x853B, 0x719B, 0x8558, 0x71D4, 0x85E0, 0x72B0, 0x8642, 0x73D4, 0x8661, 0x74B3, 0x8616, 0x74AD, 0x84D7, 0x74B2, 0x84B3, 0x74B5, 0x849B, 0x751E, 0x8496, 0x753B, 0x84B8, 0x75C5, 0x856E, 0x756D, 0x865A, 0x74D0, 0x86B8, 0x73FA, 0x86EA, 0x7250, 0x86CF, 0x70E7, 0x863F, 0x707E, 0x85C8, 0x705F, 0x8549, 0x7075, 0x84CC, 0x70AC, 0x8475, 0x70CD, 0x8452, 0x71FF, 0x839C, 0x7287, 0x8376, 0x736A, 0x833A, 0x7443, 0x8319, 0x751E, 0x8311, 0x76AC, 0x8327, 0x77C4, 0x8341, 0x7810, 0x8340, 0x799F, 0x8313, 0x7A2A, 0x82EA, 0x7B24, 0x8281, 0x7BE4, 0x820C, 0x7BEC, 0x81B1, 0x7A5E, 0x81C8, 0x7809, 0x81ED, 0x7751, 0x81F8, 0x7664, 0x81EF, 0x7571, 0x81B4, 0x74BB, 0x8141, 0x7483, 0x80F9, 0x7408, 0x802F, 0x73D9, 0x7FEB, 0x7359, 0x7F50, 0x72A0, 0x7EC4, 0x719E, 0x7E89, 0x7074, 0x7EA8, 0x7015, 0x7ECC, 0x6FD0, 0x7EF8, 0x6FA3, 0x7F19, 0x6F6B, 0x7FBB, 0x6F93, 0x8017, 0x6FA7, 0x8032, 0x6FD7, 0x805A, 0x70DF, 0x8092, 0x7205, 0x805A, 0x729E, 0x7FCB, 0x72B3, 0x7FBC, 0x7309, 0x7FA6, 0x733B, 0x7FDE, 0x72F9, 0x804B, 0x726D, 0x80A7, 0x70E6, 0x80FB, 0x700D, 0x80EC, 0x6F48, 0x80A8, 0x6EFC, 0x8073, 0x6EC1, 0x8026, 0x6E93, 0x7FCC, 0x6ED4, 0x7ED8, 0x6F54, 0x7E72, 0x6FCB, 0x7E3A, 0x700B, 0x7E25, 0x71AB, 0x7DED, 0x7356, 0x7E3E, 0x7472, 0x7EF4, 0x7536, 0x7FBD, 0x75DA, 0x8075, 0x7628, 0x80B6, 0x767B, 0x80D8, 0x76D9, 0x80EF, 0x7755, 0x80FC, 0x7881, 0x80D5, 0x7931, 0x8093, 0x7A00, 0x801E, 0x799B, 0x7D9B, 0x789A, 0x7CD8, 0x77C0, 0x7BE5, 0x7783, 0x7B55, 0x7787, 0x7AB9, 0x77AE, 0x7A67, 0x77E6, 0x7A1D, 0x781E, 0x79CD, 0x785E, 0x7909, 0x7853, 0x78C0, 0x7823, 0x788B, 0x7808, 0x7875, 0x7649, 0x77E8, 0x74B6, 0x7869, 0x7488, 0x78B3, 0x7472, 0x7901, 0x74D2, 0x796F, 0x75D8, 0x799A, 0x76EE, 0x7971, 0x774A, 0x797A, 0x7751, 0x79B4, 0x76A0, 0x79F0, 0x75E4, 0x7A0A, 0x7454, 0x79E1, 0x73AF, 0x7986, 0x7369, 0x7909, 0x7374, 0x7891, 0x739D, 0x783C, 0x73B6, 0x781E, 0x74B7, 0x7768, 0x765D, 0x772C, 0x77ED, 0x7769, 0x7932, 0x77FC, 0x7979, 0x7836, 0x79B8, 0x787B, 0x79DF, 0x7912, 0x7998, 0x7A14, 0x7967, 0x7AB4, 0x796A, 0x7AD8, 0x79C5, 0x7B60, 0x7A9D, 0x7BE9, 0x7B72, 0x7C47, 0x7EBA, 0x7BD6, 0x8206, 0x7CA8, 0x82FA, 0x7C2E, 0x8391, 0x7BB4, 0x83F6, 0x7B40, 0x8413, 0x7AD0, 0x83DD, 0x7A71, 0x838A, 0x7A39, 0x8296, 0x79B7, 0x80F3, 0x78FA, 0x8016, 0x788A, 0x7FB4, 0x7833, 0x7F8D, 0x77DF, 0x7F92, 0x77A9, 0x7FB3, 0x7718, 0x7FF6, 0x76C2, 0x8036, 0x768A, 0x8097, 0x764A, 0x80DF, 0x762A, 0x813C, 0x7605, 0x8275, 0x75D5}; + +#define LOGO_BACKGROUND 0xDEEA5C + +#define LOGO_PAINT_PATHS \ + LOGO_PAINT_PATH(0xC1D82F, logo_green) \ + LOGO_PAINT_PATH(0x000000, logo_black) \ + LOGO_PAINT_PATH(0x000000, logo_type) \ + LOGO_PAINT_PATH(0x000000, logo_mark) \ + LOGO_PAINT_PATH(0xFFFFFF, logo_white) diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/colors.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/colors.h new file mode 100644 index 0000000..cdcf00a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/colors.h @@ -0,0 +1,183 @@ +/************ + * colors.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +namespace Theme { + #if ENABLED(TOUCH_UI_COCOA_THEME) + constexpr int accent_hue = 23; + + // Browns and Oranges + constexpr uint32_t accent_color_1 = hsl_to_rgb(12.8,0.597,0.263); // Darkest + constexpr uint32_t accent_color_2 = hsl_to_rgb(12.8,0.597,0.263); + constexpr uint32_t accent_color_3 = hsl_to_rgb( 9.6,0.664,0.443); + constexpr uint32_t accent_color_4 = hsl_to_rgb(16.3,0.873,0.537); + constexpr uint32_t accent_color_5 = hsl_to_rgb(23.0,0.889,0.539); + constexpr uint32_t accent_color_6 = hsl_to_rgb(23.0,0.889,0.539); // Lightest + #else + // Use linear accent colors + + #if ANY(TOUCH_UI_ROYAL_THEME, TOUCH_UI_FROZEN_THEME) + // Dark blue accent colors + constexpr int accent_hue = 216; + constexpr float accent_sat = 0.7; + #else + // Green accent colors + constexpr int accent_hue = 68; + constexpr float accent_sat = 0.68; + #endif + + // Shades of accent color + constexpr uint32_t accent_color_0 = hsl_to_rgb(accent_hue, accent_sat, 0.15); // Darkest + constexpr uint32_t accent_color_1 = hsl_to_rgb(accent_hue, accent_sat, 0.26); + constexpr uint32_t accent_color_2 = hsl_to_rgb(accent_hue, accent_sat, 0.39); + constexpr uint32_t accent_color_3 = hsl_to_rgb(accent_hue, accent_sat, 0.52); + constexpr uint32_t accent_color_4 = hsl_to_rgb(accent_hue, accent_sat, 0.65); + constexpr uint32_t accent_color_5 = hsl_to_rgb(accent_hue, accent_sat, 0.78); + constexpr uint32_t accent_color_6 = hsl_to_rgb(accent_hue, accent_sat, 0.91); // Lightest + #endif + + // Shades of gray + + constexpr float gray_sat = 0.14; + constexpr uint32_t gray_color_0 = hsl_to_rgb(accent_hue, gray_sat, 0.15); // Darkest + constexpr uint32_t gray_color_1 = hsl_to_rgb(accent_hue, gray_sat, 0.26); + constexpr uint32_t gray_color_2 = hsl_to_rgb(accent_hue, gray_sat, 0.39); + constexpr uint32_t gray_color_3 = hsl_to_rgb(accent_hue, gray_sat, 0.52); + constexpr uint32_t gray_color_4 = hsl_to_rgb(accent_hue, gray_sat, 0.65); + constexpr uint32_t gray_color_5 = hsl_to_rgb(accent_hue, gray_sat, 0.78); + constexpr uint32_t gray_color_6 = hsl_to_rgb(accent_hue, gray_sat, 0.91); // Lightest + + #if ENABLED(TOUCH_UI_ROYAL_THEME) + constexpr uint32_t theme_darkest = accent_color_1; + constexpr uint32_t theme_dark = accent_color_4; + + constexpr uint32_t bg_color = gray_color_0; + constexpr uint32_t axis_label = gray_color_1; + + constexpr uint32_t bg_text_enabled = accent_color_6; + constexpr uint32_t bg_text_disabled = gray_color_0; + constexpr uint32_t bg_normal = accent_color_4; + constexpr uint32_t fg_disabled = gray_color_0; + constexpr uint32_t fg_normal = accent_color_0; + constexpr uint32_t fg_action = accent_color_1; + + constexpr uint32_t logo_bg_rgb = accent_color_1; + constexpr uint32_t logo_fill_rgb = accent_color_0; + constexpr uint32_t logo_stroke_rgb = accent_color_4; + #elif ANY(TOUCH_UI_COCOA_THEME, TOUCH_UI_FROZEN_THEME) + constexpr uint32_t theme_darkest = accent_color_1; + constexpr uint32_t theme_dark = accent_color_4; + + constexpr uint32_t bg_color = 0xFFFFFF; + constexpr uint32_t axis_label = gray_color_5; + + constexpr uint32_t bg_text_enabled = accent_color_1; + constexpr uint32_t bg_text_disabled = gray_color_1; + constexpr uint32_t bg_normal = accent_color_4; + constexpr uint32_t fg_disabled = gray_color_6; + constexpr uint32_t fg_normal = accent_color_1; + constexpr uint32_t fg_action = accent_color_4; + + constexpr uint32_t logo_bg_rgb = accent_color_5; + constexpr uint32_t logo_fill_rgb = accent_color_6; + constexpr uint32_t logo_stroke_rgb = accent_color_2; + #else + constexpr uint32_t theme_darkest = gray_color_1; + constexpr uint32_t theme_dark = gray_color_2; + + constexpr uint32_t bg_color = gray_color_1; + constexpr uint32_t axis_label = gray_color_2; + + constexpr uint32_t bg_text_enabled = 0xFFFFFF; + constexpr uint32_t bg_text_disabled = gray_color_2; + constexpr uint32_t bg_normal = gray_color_1; + constexpr uint32_t fg_disabled = gray_color_1; + constexpr uint32_t fg_normal = gray_color_2; + constexpr uint32_t fg_action = accent_color_2; + + constexpr uint32_t logo_bg_rgb = accent_color_4; + constexpr uint32_t logo_fill_rgb = accent_color_3; + constexpr uint32_t logo_stroke_rgb = 0x000000; + #endif + + constexpr uint32_t shadow_rgb = gray_color_6; + constexpr uint32_t stroke_rgb = accent_color_1; + constexpr uint32_t fill_rgb = accent_color_3; + #if ENABLED(TOUCH_UI_COCOA_PRESS) + constexpr uint32_t syringe_rgb = 0xFFFFFF; + constexpr uint32_t fluid_rgb = accent_color_5; + #else + constexpr uint32_t syringe_rgb = accent_color_5; + constexpr uint32_t fluid_rgb = accent_color_3; + #endif + + #if ENABLED(TOUCH_UI_ROYAL_THEME) + constexpr uint32_t x_axis = hsl_to_rgb(0, 1.00, 0.26); + constexpr uint32_t y_axis = hsl_to_rgb(120, 1.00, 0.13); + constexpr uint32_t z_axis = hsl_to_rgb(240, 1.00, 0.10); + #else + constexpr uint32_t x_axis = hsl_to_rgb(0, 1.00, 0.5); + constexpr uint32_t y_axis = hsl_to_rgb(120, 1.00, 0.37); + constexpr uint32_t z_axis = hsl_to_rgb(240, 1.00, 0.37); + #endif + constexpr uint32_t e_axis = axis_label; + constexpr uint32_t feedrate = axis_label; + constexpr uint32_t other = axis_label; + + // Status screen + constexpr uint32_t progress = axis_label; + constexpr uint32_t status_msg = axis_label; + #if ENABLED(TOUCH_UI_ROYAL_THEME) + constexpr uint32_t fan_speed = hsl_to_rgb(240, 0.5, 0.13); + constexpr uint32_t temp = hsl_to_rgb(343, 1.0, 0.23); + #else + constexpr uint32_t fan_speed = hsl_to_rgb(204, 0.47, 0.41); + constexpr uint32_t temp = hsl_to_rgb(311, 0.51, 0.35); + #endif + + constexpr uint32_t disabled_icon = gray_color_1; + + // Calibration Registers Screen + constexpr uint32_t transformA = 0x3010D0; + constexpr uint32_t transformB = 0x4010D0; + constexpr uint32_t transformC = 0x5010D0; + constexpr uint32_t transformD = 0x6010D0; + constexpr uint32_t transformE = 0x7010D0; + constexpr uint32_t transformF = 0x8010D0; + constexpr uint32_t transformVal = 0x104010; + + constexpr btn_colors disabled_btn = {.bg = bg_color, .grad = fg_disabled, .fg = fg_disabled, .rgb = fg_disabled }; + constexpr btn_colors normal_btn = {.bg = fg_action, .grad = 0xFFFFFF, .fg = fg_normal, .rgb = 0xFFFFFF }; + constexpr btn_colors action_btn = {.bg = bg_color, .grad = 0xFFFFFF, .fg = fg_action, .rgb = 0xFFFFFF }; + constexpr btn_colors red_btn = {.bg = 0xFF5555, .grad = 0xFFFFFF, .fg = 0xFF0000, .rgb = 0xFFFFFF }; + constexpr btn_colors ui_slider = {.bg = theme_darkest, .grad = 0xFFFFFF, .fg = theme_dark, .rgb = accent_color_3 }; + constexpr btn_colors ui_toggle = {.bg = theme_darkest, .grad = 0xFFFFFF, .fg = theme_dark, .rgb = 0xFFFFFF }; + + // Temperature color scale + + const rgb_t cool_rgb ( 0, 0, 0); + const rgb_t low_rgb (128, 0, 0); + const rgb_t med_rgb (255, 128, 0); + const rgb_t high_rgb (255, 255, 128); +}; diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/fonts.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/fonts.h new file mode 100644 index 0000000..7cc4e07 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/fonts.h @@ -0,0 +1,80 @@ +/*********** + * fonts.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +namespace Theme { + #ifdef TOUCH_UI_800x480 + #if ENABLED(TOUCH_UI_PORTRAIT) + constexpr int16_t font_tiny = 26; + constexpr int16_t font_xsmall = 28; + constexpr int16_t font_small = 29; + constexpr int16_t font_medium = 30; + constexpr int16_t font_large = 30; + constexpr int16_t font_xlarge = 31; + #else + constexpr int16_t font_tiny = 27; + constexpr int16_t font_xsmall = 29; + constexpr int16_t font_small = 30; + constexpr int16_t font_medium = 30; + constexpr int16_t font_large = 31; + constexpr int16_t font_xlarge = 31; + #endif + constexpr float icon_scale = 1.0; + #elif defined(TOUCH_UI_480x272) + #if ENABLED(TOUCH_UI_PORTRAIT) + constexpr int16_t font_tiny = 26; + constexpr int16_t font_xsmall = 26; + constexpr int16_t font_small = 26; + constexpr int16_t font_medium = 27; + constexpr int16_t font_large = 28; + constexpr int16_t font_xlarge = 29; + constexpr float icon_scale = 0.7; + #else + constexpr int16_t font_tiny = 26; + constexpr int16_t font_xsmall = 26; + constexpr int16_t font_small = 27; + constexpr int16_t font_medium = 28; + constexpr int16_t font_large = 30; + constexpr int16_t font_xlarge = 31; + constexpr float icon_scale = 0.6; + #endif + #elif defined(TOUCH_UI_320x240) + #if ENABLED(TOUCH_UI_PORTRAIT) + constexpr int16_t font_tiny = 26; + constexpr int16_t font_xsmall = 26; + constexpr int16_t font_small = 26; + constexpr int16_t font_medium = 27; + constexpr int16_t font_large = 27; + constexpr int16_t font_xlarge = 28; + constexpr float icon_scale = 0.6; + #else + constexpr int16_t font_tiny = 26; + constexpr int16_t font_xsmall = 26; + constexpr int16_t font_small = 26; + constexpr int16_t font_medium = 27; + constexpr int16_t font_large = 29; + constexpr int16_t font_xlarge = 30; + constexpr float icon_scale = 0.5; + #endif + #endif +} diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_landscape.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_landscape.h new file mode 100644 index 0000000..e023599 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_landscape.h @@ -0,0 +1,39 @@ + +/**************************************************************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/** + * 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 logo_fill[] = {0x419D, 0x546F, 0x3D05, 0x5615, 0x3942, 0x5A92, 0x36B7, 0x6136, 0x35C8, 0x6950, 0x35C8, 0x96B0, 0x36B7, 0x9ECA, 0x3942, 0xA56E, 0x3D05, 0xA9EB, 0x419D, 0xAB91, 0xBE60, 0xAB91, 0xC2F8, 0xA9EB, 0xC6BB, 0xA56E, 0xC946, 0x9ECA, 0xCA35, 0x96B0, 0xCA32, 0x546C, 0x419D, 0x546F}; + +const PROGMEM uint16_t logo_stroke[] = {0xADF3, 0x546C, 0x419D, 0x546F, 0x3D05, 0x5615, 0x3942, 0x5A92, 0x36B7, 0x6136, 0x35C8, 0x6950, 0x35C8, 0x96B0, 0x36B7, 0x9ECA, 0x3942, 0xA56E, 0x3D05, 0xA9EB, 0x419D, 0xAB91, 0xBE60, 0xAB91, 0xC2F8, 0xA9EB, 0xC6BB, 0xA56E, 0xC946, 0x9ECA, 0xCA35, 0x96B0, 0xCA32, 0x546C, 0xADF3, 0x546C, 0xFFFF, 0x419D, 0x5913, 0xB08C, 0x5913, 0xC794, 0x8250, 0xC794, 0x96B0, 0xC6DA, 0x9CFF, 0xC4E1, 0xA229, 0xC1F4, 0xA5A5, 0xBE60, 0xA6ED, 0x419D, 0xA6ED, 0x3E09, 0xA5A5, 0x3B1C, 0xA229, 0x3923, 0x9CFF, 0x3869, 0x96B0, 0x3869, 0x6950, 0x3923, 0x6301, 0x3B1C, 0x5DD7, 0x3E09, 0x5A5B, 0x419D, 0x5913, 0xFFFF, 0xAC7A, 0x8620, 0xAC7A, 0x9373, 0xA767, 0x9373, 0xA767, 0x75CB, 0xA1C6, 0x75CB, 0xA1C6, 0x9373, 0xA1C6, 0x9C8E, 0xA767, 0x9C8E, 0xAC7A, 0x9C8E, 0xB21C, 0x9C8E, 0xB21C, 0x9373, 0xB21C, 0x85E7, 0xB350, 0x8093, 0xB65F, 0x7E86, 0xB9D5, 0x8165, 0xBA83, 0x85E7, 0xBA83, 0x9C8E, 0xBEFE, 0x9C8E, 0xC024, 0x99E1, 0xC024, 0x8620, 0xBF7B, 0x7F22, 0xBD8F, 0x79A9, 0xBA7E, 0x7617, 0xB65F, 0x74D0, 0xB24F, 0x7622, 0xAF30, 0x79C6, 0xAD2F, 0x7F43, 0xAC7A, 0x8620, 0xAC7A, 0x8620, 0xAC7A, 0x8620, 0xFFFF, 0x8179, 0x9C8E, 0x7CE9, 0x9C8E, 0x7747, 0x9C8E, 0x7747, 0x92EC, 0x7747, 0x8949, 0x75A2, 0x81A3, 0x71A6, 0x7E73, 0x6DAB, 0x818B, 0x6C05, 0x88FC, 0x6DAF, 0x9019, 0x71C7, 0x92EC, 0x7505, 0x92EC, 0x7505, 0x9C8E, 0x7118, 0x9C8E, 0x6CD3, 0x9B06, 0x696B, 0x96D6, 0x6729, 0x909E, 0x6658, 0x88FC, 0x672D, 0x8133, 0x6980, 0x7AC7, 0x6D13, 0x766C, 0x71A6, 0x74D0, 0x7632, 0x766D, 0x79C2, 0x7AD1, 0x7C14, 0x8153, 0x7CE9, 0x8949, 0x7CE9, 0x92EC, 0x8179, 0x92EC, 0x8179, 0x8620, 0x822E, 0x7F43, 0x842E, 0x79C6, 0x874E, 0x7622, 0x8B5E, 0x74D0, 0x8F7C, 0x7617, 0x928E, 0x79A9, 0x9479, 0x7F22, 0x9523, 0x8620, 0x9523, 0x87DB, 0x8F81, 0x87DB, 0x8F81, 0x85E7, 0x8ED4, 0x8165, 0x8B5E, 0x7E86, 0x884F, 0x8093, 0x871A, 0x85E7, 0x871A, 0x92EC, 0x871A, 0x9C8F, 0x8179, 0x9C8F, 0x8179, 0x9C8E, 0x8179, 0x9C8E, 0xFFFF, 0x6515, 0x79DB, 0x644C, 0x7281, 0x6218, 0x6C86, 0x5EB2, 0x6882, 0x5A56, 0x670A, 0x55D9, 0x68E0, 0x5272, 0x6DD0, 0x4F0B, 0x68E0, 0x4A8E, 0x670A, 0x4638, 0x6882, 0x42D5, 0x6C86, 0x40A2, 0x7281, 0x3FD9, 0x79DB, 0x3FD9, 0x9AC9, 0x40E4, 0x9C8E, 0x456F, 0x9C8E, 0x456F, 0x79B5, 0x46D4, 0x735D, 0x4A8E, 0x70C0, 0x4E3E, 0x735D, 0x4FA1, 0x79B5, 0x4FA1, 0x9C8E, 0x554D, 0x9C8E, 0x554D, 0x79B5, 0x56A7, 0x735D, 0x5A56, 0x70C0, 0x5E0C, 0x735D, 0x5F74, 0x79B5, 0x5F74, 0x9C8E, 0x6515, 0x9C8E, 0x6515, 0x79DB, 0x6515, 0x79DB, 0x6515, 0x79DB, 0xFFFF, 0x9672, 0x8C4C, 0x9714, 0x9379, 0x98F5, 0x98D2, 0x9C0B, 0x9BF4, 0xA04C, 0x9C7B, 0xA04C, 0x9373, 0x9D2B, 0x920C, 0x9C1E, 0x8C4C, 0x9C1E, 0x648E, 0x9672, 0x648E, 0x9672, 0x8C4C, 0x9672, 0x8C4C, 0x9672, 0x8C4C, 0xFFFF, 0xA767, 0x7194, 0xA767, 0x6C02, 0xA692, 0x687A, 0xA496, 0x670A, 0xA291, 0x687A, 0xA1BB, 0x6C02, 0xA1BB, 0x7194, 0xA767, 0x7194, 0xA767, 0x7194, 0xA767, 0x7194}; + +#define LOGO_BACKGROUND logo_bg_rgb +#define LOGO_PAINT_PATHS \ + LOGO_PAINT_PATH(logo_fill_rgb, logo_fill) \ + LOGO_PAINT_PATH(logo_stroke_rgb, logo_stroke) diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_portrait.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_portrait.h new file mode 100644 index 0000000..e3a30a6 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/marlin_bootscreen_portrait.h @@ -0,0 +1,39 @@ + +/**************************************************************************** + * 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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +/** + * 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 logo_fill[] = {0x3C19, 0x70C5, 0x371A, 0x7159, 0x3302, 0x72EA, 0x303D, 0x753C, 0x2F39, 0x7811, 0x2F39, 0x87ED, 0x303D, 0x8AC2, 0x3302, 0x8D14, 0x371A, 0x8EA5, 0x3C19, 0x8F39, 0xC3E4, 0x8F39, 0xC8E3, 0x8EA5, 0xCCFB, 0x8D14, 0xCFC0, 0x8AC2, 0xD0C4, 0x87ED, 0xD0C0, 0x70C4, 0x3C19, 0x70C5}; + +const PROGMEM uint16_t logo_stroke[] = {0x3C19, 0x70C5, 0x371A, 0x7159, 0x3302, 0x72EA, 0x303D, 0x753C, 0x2F39, 0x7811, 0x2F39, 0x87ED, 0x303D, 0x8AC2, 0x3302, 0x8D14, 0x371A, 0x8EA5, 0x3C19, 0x8F39, 0xC3E4, 0x8F39, 0xC8E3, 0x8EA5, 0xCCFB, 0x8D14, 0xCFC0, 0x8AC2, 0xD0C4, 0x87ED, 0xD0C0, 0x70C4, 0x3C19, 0x70C5, 0xFFFF, 0x3C19, 0x7264, 0xB4D6, 0x7264, 0xCDE7, 0x80CE, 0xCDE7, 0x87ED, 0xCD1D, 0x8A21, 0xCAF7, 0x8BEF, 0xC7C8, 0x8D27, 0xC3E4, 0x8D9A, 0x3C19, 0x8D9A, 0x3835, 0x8D27, 0x3506, 0x8BEF, 0x32E0, 0x8A21, 0x3216, 0x87ED, 0x3216, 0x7811, 0x32E0, 0x75DD, 0x3506, 0x740F, 0x3835, 0x72D7, 0x3C19, 0x7264, 0xFFFF, 0xB069, 0x8223, 0xB069, 0x86CB, 0xAAE2, 0x86CB, 0xAAE2, 0x7C6E, 0xA4C2, 0x7C6E, 0xA4C2, 0x86CB, 0xA4C2, 0x89FA, 0xAAE2, 0x89FA, 0xB069, 0x89FA, 0xB689, 0x89FA, 0xB689, 0x86CB, 0xB689, 0x820F, 0xB7D9, 0x8033, 0xBB2E, 0x7F7B, 0xBEF2, 0x807C, 0xBFAE, 0x820F, 0xBFAE, 0x89FA, 0xC48F, 0x89FA, 0xC5CF, 0x890A, 0xC5CF, 0x8223, 0xC517, 0x7FB2, 0xC300, 0x7DC8, 0xBFA9, 0x7C88, 0xBB2E, 0x7C16, 0xB6C1, 0x7C8C, 0xB35B, 0x7DD2, 0xB12D, 0x7FBD, 0xB069, 0x8223, 0xB069, 0x8223, 0xB069, 0x8223, 0xFFFF, 0x819B, 0x89FA, 0x7CA3, 0x89FA, 0x7682, 0x89FA, 0x7682, 0x869C, 0x7682, 0x833E, 0x74B7, 0x8092, 0x7062, 0x7F74, 0x6C0C, 0x8089, 0x6A41, 0x8323, 0x6C10, 0x859F, 0x7085, 0x869C, 0x740C, 0x869C, 0x740C, 0x89FA, 0x6FC7, 0x89FA, 0x6B21, 0x8971, 0x676C, 0x87FA, 0x64F8, 0x85CE, 0x6414, 0x8323, 0x64FC, 0x806A, 0x6784, 0x7E2C, 0x6B67, 0x7CA6, 0x7062, 0x7C16, 0x7555, 0x7CA6, 0x7935, 0x7E2F, 0x7BBC, 0x8076, 0x7CA3, 0x833E, 0x7CA3, 0x869C, 0x819A, 0x869C, 0x819A, 0x8223, 0x825F, 0x7FBD, 0x848D, 0x7DD2, 0x87F3, 0x7C8C, 0x8C60, 0x7C16, 0x90DB, 0x7C88, 0x9432, 0x7DC8, 0x9648, 0x7FB2, 0x9701, 0x8223, 0x9701, 0x82BE, 0x90E0, 0x82BE, 0x90E0, 0x820F, 0x9024, 0x807C, 0x8C60, 0x7F7B, 0x890B, 0x8033, 0x87BB, 0x820F, 0x87BB, 0x869C, 0x87BB, 0x89FA, 0x819B, 0x89FA, 0x819B, 0x89FA, 0x819B, 0x89FA, 0xFFFF, 0x62B5, 0x7DD9, 0x61DA, 0x7B47, 0x5F73, 0x7931, 0x5BC1, 0x77C9, 0x5702, 0x7746, 0x521F, 0x77EA, 0x4E6B, 0x79A4, 0x4AB8, 0x77EA, 0x45D5, 0x7746, 0x411D, 0x77C9, 0x3D6E, 0x7931, 0x3B09, 0x7B47, 0x3A2E, 0x7DD9, 0x3A2E, 0x895C, 0x3B51, 0x89FA, 0x4043, 0x89FA, 0x4043, 0x7DCC, 0x41C6, 0x7B95, 0x45D5, 0x7AAB, 0x49D9, 0x7B95, 0x4B5B, 0x7DCC, 0x4B5B, 0x89FA, 0x5188, 0x89FA, 0x5188, 0x7DCC, 0x52FF, 0x7B95, 0x5702, 0x7AAB, 0x5B0C, 0x7B95, 0x5C94, 0x7DCC, 0x5C94, 0x89FA, 0x62B5, 0x89FA, 0x62B5, 0x7DD9, 0x62B5, 0x7DD9, 0x62B5, 0x7DD9, 0xFFFF, 0x986E, 0x844B, 0x991E, 0x86CD, 0x9B2A, 0x88AC, 0x9E85, 0x89C4, 0xA327, 0x89F3, 0xA327, 0x86CB, 0x9FBF, 0x864E, 0x9E9A, 0x844B, 0x9E9A, 0x7668, 0x986E, 0x7668, 0x986E, 0x844B, 0x986E, 0x844B, 0x986E, 0x844B, 0xFFFF, 0xAAE2, 0x7AF5, 0xAAE2, 0x7902, 0xA9FB, 0x77C7, 0xA7D2, 0x7746, 0xA59F, 0x77C7, 0xA4B6, 0x7902, 0xA4B6, 0x7AF5, 0xAAE2, 0x7AF5, 0xAAE2, 0x7AF5, 0xAAE2, 0x7AF5}; + +#define LOGO_BACKGROUND logo_bg_rgb +#define LOGO_PAINT_PATHS \ + LOGO_PAINT_PATH(logo_fill_rgb, logo_fill) \ + LOGO_PAINT_PATH(logo_stroke_rgb, logo_stroke) diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.cpp b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.cpp new file mode 100644 index 0000000..afbed0c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.cpp @@ -0,0 +1,410 @@ +/************** + * sounds.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../compat.h" + +#if ENABLED(TOUCH_UI_FTDI_EVE) + +#include "../ftdi_eve_lib/ftdi_eve_lib.h" + +#include "sounds.h" + +namespace Theme { + using namespace FTDI; + + const PROGMEM SoundPlayer::sound_t chimes[] = { + {CHIMES, NOTE_G3, 5}, + {CHIMES, NOTE_E4, 5}, + {CHIMES, NOTE_C4, 5}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t sad_trombone[] = { + {TRUMPET, NOTE_A3S, 10}, + {TRUMPET, NOTE_A3 , 10}, + {TRUMPET, NOTE_G3S, 10}, + {TRUMPET, NOTE_G3, 20}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t twinkle[] = { + {GLOCKENSPIEL, NOTE_C4, 1}, + {GLOCKENSPIEL, NOTE_E4, 1}, + {GLOCKENSPIEL, NOTE_G4, 16}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t fanfare[] = { + {TRUMPET, NOTE_A3, 4}, + {SILENCE, REST, 1}, + {TRUMPET, NOTE_A3, 2}, + {SILENCE, REST, 1}, + {TRUMPET, NOTE_A3, 2}, + {SILENCE, REST, 1}, + {TRUMPET, NOTE_E4, 10}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t media_inserted[] = { + {MUSIC_BOX, NOTE_C4, 2}, + {MUSIC_BOX, NOTE_E4, 2}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t media_removed[] = { + {MUSIC_BOX, NOTE_E4, 2}, + {MUSIC_BOX, NOTE_C4, 2}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t js_bach_toccata[] = { + {ORGAN, NOTE_A4, 2}, + {ORGAN, NOTE_G4, 2}, + {ORGAN, NOTE_A4, 35}, + {SILENCE, REST, 12}, + {ORGAN, NOTE_G4, 4}, + {ORGAN, NOTE_F4, 4}, + {ORGAN, NOTE_E4, 4}, + {ORGAN, NOTE_D4, 4}, + {ORGAN, NOTE_C4S, 16}, + {ORGAN, NOTE_D4, 32}, + {SILENCE, REST, 42}, + + {ORGAN, NOTE_A3, 2}, + {ORGAN, NOTE_G3, 2}, + {ORGAN, NOTE_A3, 35}, + {SILENCE, REST, 9}, + {ORGAN, NOTE_E3, 8}, + {ORGAN, NOTE_F3, 8}, + {ORGAN, NOTE_C3S, 16}, + {ORGAN, NOTE_D3, 27}, + {SILENCE, REST, 42}, + + {ORGAN, NOTE_A2, 2}, + {ORGAN, NOTE_G2, 2}, + {ORGAN, NOTE_A2, 35}, + {SILENCE, REST, 12}, + {ORGAN, NOTE_G2, 4}, + {ORGAN, NOTE_F2, 4}, + {ORGAN, NOTE_E2, 4}, + {ORGAN, NOTE_D2, 4}, + {ORGAN, NOTE_C2S, 16}, + {ORGAN, NOTE_D2, 32}, + {SILENCE, REST, 52}, + + //{ORGAN, NOTE_D1, 28}, + {ORGAN, NOTE_C3S, 9}, + {ORGAN, NOTE_E3, 9}, + {ORGAN, NOTE_G3, 9}, + {ORGAN, NOTE_A3S, 9}, + {ORGAN, NOTE_C4S, 9}, + {ORGAN, NOTE_E4, 9}, + {ORGAN, NOTE_D4, 20}, + {SILENCE, REST, 30}, + + {ORGAN, NOTE_C4S, 4}, + {ORGAN, NOTE_D4, 2}, + {ORGAN, NOTE_E4, 2}, + + {ORGAN, NOTE_C4S, 2}, + {ORGAN, NOTE_D4, 2}, + {ORGAN, NOTE_E4, 2}, + + {ORGAN, NOTE_C4S, 2}, + {ORGAN, NOTE_D4, 2}, + {ORGAN, NOTE_E4, 2}, + + {ORGAN, NOTE_C4S, 2}, + {ORGAN, NOTE_D4, 4}, + {ORGAN, NOTE_E4, 4}, + {ORGAN, NOTE_F4, 2}, + {ORGAN, NOTE_G4, 2}, + + {ORGAN, NOTE_E4, 2}, + {ORGAN, NOTE_F4, 2}, + {ORGAN, NOTE_G4, 2}, + + {ORGAN, NOTE_E4, 2}, + {ORGAN, NOTE_F4, 2}, + {ORGAN, NOTE_G4, 2}, + + {ORGAN, NOTE_E4, 2}, + {ORGAN, NOTE_F4, 4}, + {ORGAN, NOTE_G4, 4}, + {ORGAN, NOTE_A4, 2}, + {ORGAN, NOTE_A4S, 2}, + + {ORGAN, NOTE_G4, 2}, + {ORGAN, NOTE_A4, 2}, + {ORGAN, NOTE_A4S, 2}, + + {ORGAN, NOTE_G4, 2}, + {ORGAN, NOTE_A4, 2}, + {ORGAN, NOTE_A4S, 2}, + + {ORGAN, NOTE_G4, 2}, + {ORGAN, NOTE_A4, 4}, + {SILENCE, REST, 36}, + + + {ORGAN, NOTE_C5S, 4}, + {ORGAN, NOTE_D5, 2}, + {ORGAN, NOTE_E5, 2}, + + {ORGAN, NOTE_C5S, 2}, + {ORGAN, NOTE_D5, 2}, + {ORGAN, NOTE_E5, 2}, + + {ORGAN, NOTE_C5S, 2}, + {ORGAN, NOTE_D5, 2}, + {ORGAN, NOTE_E5, 2}, + + {ORGAN, NOTE_C5S, 2}, + {ORGAN, NOTE_D5, 4}, + {ORGAN, NOTE_E5, 4}, + {ORGAN, NOTE_F5, 2}, + {ORGAN, NOTE_G5, 2}, + + {ORGAN, NOTE_E5, 2}, + {ORGAN, NOTE_F5, 2}, + {ORGAN, NOTE_G5, 2}, + + {ORGAN, NOTE_E5, 2}, + {ORGAN, NOTE_F5, 2}, + {ORGAN, NOTE_G5, 2}, + + {ORGAN, NOTE_E5, 2}, + {ORGAN, NOTE_F5, 4}, + {ORGAN, NOTE_G5, 4}, + {ORGAN, NOTE_A5, 2}, + {ORGAN, NOTE_A5S, 2}, + + {ORGAN, NOTE_G5, 2}, + {ORGAN, NOTE_A5, 2}, + {ORGAN, NOTE_A5S, 2}, + + {ORGAN, NOTE_G5, 2}, + {ORGAN, NOTE_A5, 2}, + {ORGAN, NOTE_A5S, 2}, + + {ORGAN, NOTE_G5, 2}, + {ORGAN, NOTE_A5, 4}, + {SILENCE, REST, 32}, + + {ORGAN, NOTE_A5, 4}, + {ORGAN, NOTE_G5, 2}, + {ORGAN, NOTE_A5S, 2}, + + {ORGAN, NOTE_E5, 2}, + {ORGAN, NOTE_G5, 2}, + {ORGAN, NOTE_A5S, 2}, + + {ORGAN, NOTE_E5, 2}, + {ORGAN, NOTE_F5, 2}, + {ORGAN, NOTE_A5, 2}, + + {ORGAN, NOTE_D5, 2}, + {ORGAN, NOTE_F5, 2}, + {ORGAN, NOTE_G5, 2}, + + {ORGAN, NOTE_D5, 2}, + {ORGAN, NOTE_E5, 2}, + {ORGAN, NOTE_A5, 2}, + + {ORGAN, NOTE_C5, 2}, + {ORGAN, NOTE_E5, 2}, + {ORGAN, NOTE_A5, 2}, + + {ORGAN, NOTE_C5, 2}, + {ORGAN, NOTE_D5, 2}, + {ORGAN, NOTE_F5, 2}, + + {ORGAN, NOTE_A4S, 2}, + {ORGAN, NOTE_D5, 2}, + {ORGAN, NOTE_E5, 2}, + + {ORGAN, NOTE_A4S, 2}, + {ORGAN, NOTE_C5, 2}, + {ORGAN, NOTE_E5, 2}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t js_bach_joy[] = { + {PIANO, NOTE_G3, 4}, + {PIANO, NOTE_A3, 4}, + {PIANO, NOTE_B3, 4}, + {PIANO, NOTE_D4, 3}, + {SILENCE, REST, 1}, + + {PIANO, NOTE_C4, 3}, + {SILENCE, REST, 1}, + {PIANO, NOTE_C4, 4}, + {PIANO, NOTE_E4, 3}, + {SILENCE, REST, 1}, + {PIANO, NOTE_D4, 2}, + {SILENCE, REST, 2}, + + {PIANO, NOTE_D4, 4}, + {PIANO, NOTE_G4 , 3}, + {SILENCE, REST, 1}, + {PIANO, NOTE_F4S, 4}, + {PIANO, NOTE_G4, 4}, + + {PIANO, NOTE_D4, 2}, + {SILENCE, REST, 2}, + {PIANO, NOTE_B3, 3}, + {SILENCE, REST, 1}, + {PIANO, NOTE_G3, 4}, + {PIANO, NOTE_A3, 2}, + {SILENCE, REST, 2}, + + {PIANO, NOTE_B3, 2}, + {SILENCE, REST, 2}, + {PIANO, NOTE_C4, 4}, + {PIANO, NOTE_D4, 2}, + {SILENCE, REST, 2}, + {PIANO, NOTE_E4, 2}, + {SILENCE, REST, 2}, + + {PIANO, NOTE_D4, 4}, + {PIANO, NOTE_C4, 2}, + {SILENCE, REST, 2}, + {PIANO, NOTE_B3, 2}, + {SILENCE, REST, 2}, + {PIANO, NOTE_A3, 4}, + + {PIANO, NOTE_B3, 2}, + {SILENCE, REST, 2}, + {PIANO, NOTE_G3, 2}, + {SILENCE, REST, 2}, + {PIANO, NOTE_G3, 8}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t big_band[] = { + {XYLOPHONE, NOTE_F4, 3}, + {XYLOPHONE, NOTE_G4, 3}, + {XYLOPHONE, NOTE_F4, 3}, + {XYLOPHONE, NOTE_D4, 3}, + {XYLOPHONE, NOTE_A3S, 3}, + {SILENCE, REST, 3}, + + {TRUMPET, NOTE_F4, 3}, + {TRUMPET, NOTE_G4, 3}, + {TRUMPET, NOTE_F4, 3}, + {TRUMPET, NOTE_D4, 3}, + {TRUMPET, NOTE_A3S, 3}, + {SILENCE, REST, 3}, + + {TUBA, NOTE_A2S, 6}, + {TUBA, NOTE_A2S, 6}, + {TUBA, NOTE_A2S, 4}, + {TUBA, NOTE_A2S, 6}, + {TUBA, NOTE_A2S, 6}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t beats[] = { + {SILENCE, REST, 8}, + {NOTCH, NOTE_C4, 8}, + {KICKDRUM, NOTE_C4, 8}, + {HIHAT, NOTE_C4, 8}, + {COWBELL, NOTE_C4, 8}, + {SILENCE, REST, 8}, + {NOTCH, NOTE_C4, 8}, + {KICKDRUM, NOTE_C4, 8}, + {HIHAT, NOTE_C4, 8}, + {COWBELL, NOTE_C4, 8}, + {SILENCE, REST, 8}, + {NOTCH, NOTE_C4, 8}, + {KICKDRUM, NOTE_C4, 8}, + {HIHAT, NOTE_C4, 8}, + {COWBELL, NOTE_C4, 8}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t beeping[] = { + {BEEPING, NOTE_C4, 64}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t alarm[] = { + {ALARM, NOTE_C4, 64}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t warble[] = { + {WARBLE, NOTE_C4, 64}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t carousel[] = { + {CAROUSEL, NOTE_C4, 64}, + {SILENCE, END_SONG, 0} + }; + + const PROGMEM SoundPlayer::sound_t all_instruments[] = { + {HARP}, + {XYLOPHONE}, + {TUBA}, + {GLOCKENSPIEL}, + {ORGAN}, + {TRUMPET}, + {PIANO}, + {CHIMES}, + {MUSIC_BOX}, + {BELL}, + {CLICK}, + {SWITCH}, + {COWBELL}, + {NOTCH}, + {HIHAT}, + {KICKDRUM}, + {SWITCH}, + {POP}, + {CLACK}, + {CHACK}, + {SILENCE, END_SONG, 0} + }; +}; // namespace Theme + +#define N_ELEMENTS(a) (sizeof(a)/sizeof(a[0])) + +const SoundList::list_t SoundList::list[] = { + {"Silence", FTDI::silence}, + {"Twinkle", Theme::twinkle}, + {"Chimes", Theme::chimes}, + {"Fanfare", Theme::fanfare}, + {"Sad Trombone", Theme::sad_trombone}, + {"Big Band", Theme::big_band}, + {"Beeping", Theme::beeping}, + {"Alarm", Theme::alarm}, + {"Warble", Theme::warble}, + {"Carousel", Theme::carousel}, + {"Beats", Theme::beats}, + {"Bach Joy", Theme::js_bach_joy}, + {"Bach Toccata", Theme::js_bach_toccata} +}; + +const uint8_t SoundList::n = N_ELEMENTS(SoundList::list); + +#endif // TOUCH_UI_FTDI_EVE diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.h new file mode 100644 index 0000000..66c1cb8 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/sounds.h @@ -0,0 +1,43 @@ +/************ + * sounds.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +namespace Theme { + using namespace FTDI; + + extern const PROGMEM SoundPlayer::sound_t chimes[]; + extern const PROGMEM SoundPlayer::sound_t sad_trombone[]; + extern const PROGMEM SoundPlayer::sound_t twinkle[]; + extern const PROGMEM SoundPlayer::sound_t fanfare[]; + extern const PROGMEM SoundPlayer::sound_t media_inserted[]; + extern const PROGMEM SoundPlayer::sound_t media_removed[]; + extern const PROGMEM SoundPlayer::sound_t js_bach_toccata[]; + extern const PROGMEM SoundPlayer::sound_t js_bach_joy[]; + extern const PROGMEM SoundPlayer::sound_t big_band[]; + extern const PROGMEM SoundPlayer::sound_t beats[]; + extern const PROGMEM SoundPlayer::sound_t beeping[]; + extern const PROGMEM SoundPlayer::sound_t alarm[]; + extern const PROGMEM SoundPlayer::sound_t warble[]; + extern const PROGMEM SoundPlayer::sound_t carousel[]; + extern const PROGMEM SoundPlayer::sound_t all_instruments[]; +}; // namespace Theme diff --git a/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/theme.h b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/theme.h new file mode 100644 index 0000000..e0f0f31 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/ftdi_eve_touch_ui/theme/theme.h @@ -0,0 +1,28 @@ +/*********** + * theme.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#pragma once + +#include "bitmaps.h" +#include "colors.h" +#include "fonts.h" +#include "sounds.h" diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp new file mode 100644 index 0000000..8685bf1 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.cpp @@ -0,0 +1,303 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "../../../../inc/MarlinConfig.h" +#include "SPIFlashStorage.h" + +extern W25QXXFlash W25QXX; + +uint8_t SPIFlashStorage::m_pageData[SPI_FLASH_PageSize]; +uint32_t SPIFlashStorage::m_currentPage; +uint16_t SPIFlashStorage::m_pageDataUsed; +uint32_t SPIFlashStorage::m_startAddress; + +#if HAS_SPI_FLASH_COMPRESSION + + uint8_t SPIFlashStorage::m_compressedData[SPI_FLASH_PageSize]; + uint16_t SPIFlashStorage::m_compressedDataUsed; + + template <typename T> + static uint32_t rle_compress(T *output, uint32_t outputLength, T *input, uint32_t inputLength, uint32_t& inputProcessed) { + uint32_t count = 0, out = 0, index, i; + T pixel; + //32767 for uint16_t + //127 for uint16_t + //calculated at compile time + constexpr T max = (0xFFFFFFFF >> (8 * (4 - sizeof(T)))) / 2; + + inputProcessed = 0; + while (count < inputLength && out < outputLength) { + index = count; + pixel = input[index++]; + while (index < inputLength && index - count < max && input[index] == pixel) + index++; + if (index - count == 1) { + /* + * Failed to "replicate" the current pixel. See how many to copy. + * Avoid a replicate run of only 2-pixels after a literal run. There + * is no gain in this, and there is a risK of loss if the run after + * the two identical pixels is another literal run. So search for + * 3 identical pixels. + */ + while (index < inputLength && index - count < max && (input[index] != input[index - 1] || (index > 1 && input[index] != input[index - 2]))) + index++; + /* + * Check why this run stopped. If it found two identical pixels, reset + * the index so we can add a run. Do this twice: the previous run + * tried to detect a replicate run of at least 3 pixels. So we may be + * able to back up two pixels if such a replicate run was found. + */ + while (index < inputLength && input[index] == input[index - 1]) + index--; + // If the output buffer could overflow, stop at the remaining bytes + NOMORE(index, count + outputLength - out - 1); + output[out++] = (uint16_t)(count - index); + for (i = count; i < index; i++) + output[out++] = input[i]; + } + else { + // Need at least more 2 spaces + if (out > outputLength - 2) break; + output[out++] = (uint16_t)(index - count); + output[out++] = pixel; + } + count = index; + } + inputProcessed = count; + + // Padding + if (out == outputLength - 1) output[out++] = 0; + + return out; + } + + template <typename UT, typename T> + static uint32_t rle_uncompress(UT *output, uint32_t outputLength, UT *input, uint32_t inputLength, uint32_t &outputFilled) { + T count; + UT i; + uint32_t processedBytes = 0; + outputFilled = 0; + + while (outputLength > 0 && inputLength > 0) { + processedBytes++; + count = static_cast<T>(*input++); + inputLength--; + if (count > 0) { // Replicate run + for (i = 0; i < count && outputLength > i; i++) + output[i] = *input; + outputFilled += i; + // If copy incomplete, change the input buffer to start with remaining data in the next call + if (i < count) { + // Change to process the difference in the next call + *(input - 1) = static_cast<UT>(count - i); + return processedBytes - 1; + } + input++; + inputLength--; + processedBytes++; + } + else if (count < 0) { // literal run + count = static_cast<T>(-count); + // Copy, validating if the output have enough space + for (i = 0; i < count && outputLength > i; i++) + output[i] = input[i]; + outputFilled += i; + // If copy incomplete, change the input buffer to start with remaining data in the next call + if (i < count) { + input[i - 1] = static_cast<UT>((count - i) * -1); + // Back one + return processedBytes + i - 1; + } + input += count; + inputLength -= count; + processedBytes += count; + } + output += count; + outputLength -= count; + } + + return processedBytes; + } + +#endif // HAS_SPI_FLASH_COMPRESSION + +void SPIFlashStorage::beginWrite(uint32_t startAddress) { + m_pageDataUsed = 0; + m_currentPage = 0; + m_startAddress = startAddress; + #if HAS_SPI_FLASH_COMPRESSION + // Restart the compressed buffer, keep the pointers of the uncompressed buffer + m_compressedDataUsed = 0; + #endif +} + + +void SPIFlashStorage::endWrite() { + // Flush remaining data + #if HAS_SPI_FLASH_COMPRESSION + if (m_compressedDataUsed > 0) { + flushPage(); + savePage(m_compressedData); + } + #else + if (m_pageDataUsed > 0) flushPage(); + #endif +} + +void SPIFlashStorage::savePage(uint8_t* buffer) { + W25QXX.SPI_FLASH_BufferWrite(buffer, m_startAddress + (SPI_FLASH_PageSize * m_currentPage), SPI_FLASH_PageSize); +} + +void SPIFlashStorage::loadPage(uint8_t* buffer) { + W25QXX.SPI_FLASH_BufferRead(buffer, m_startAddress + (SPI_FLASH_PageSize * m_currentPage), SPI_FLASH_PageSize); +} + +void SPIFlashStorage::flushPage() { + #if HAS_SPI_FLASH_COMPRESSION + // Work com with compressed in memory + uint32_t inputProcessed; + uint32_t compressedSize = rle_compress<uint16_t>((uint16_t *)(m_compressedData + m_compressedDataUsed), compressedDataFree() / 2, (uint16_t *)m_pageData, m_pageDataUsed / 2, inputProcessed) * 2; + inputProcessed *= 2; + m_compressedDataUsed += compressedSize; + + // Space remaining in the compressed buffer? + if (compressedDataFree() > 0) { + // Free the uncompressed buffer + m_pageDataUsed = 0; + return; + } + + // Part of the m_pageData was compressed, so ajust the pointers, freeing what was processed, shift the buffer + // TODO: To avoid this copy, use a circular buffer + memmove(m_pageData, m_pageData + inputProcessed, m_pageDataUsed - inputProcessed); + m_pageDataUsed -= inputProcessed; + + // No? So flush page with compressed data!! + uint8_t *buffer = m_compressedData; + #else + uint8_t *buffer = m_pageData; + #endif + + savePage(buffer); + + #if HAS_SPI_FLASH_COMPRESSION + // Restart the compressed buffer, keep the pointers of the uncompressed buffer + m_compressedDataUsed = 0; + #else + m_pageDataUsed = 0; + #endif + m_currentPage++; +} + +void SPIFlashStorage::readPage() { + #if HAS_SPI_FLASH_COMPRESSION + if (compressedDataFree() == 0) { + loadPage(m_compressedData); + m_currentPage++; + m_compressedDataUsed = 0; + } + + // Need to uncompress data + if (pageDataFree() == 0) { + m_pageDataUsed = 0; + uint32_t outpuProcessed = 0; + uint32_t inputProcessed = rle_uncompress<uint16_t, int16_t>((uint16_t *)(m_pageData + m_pageDataUsed), pageDataFree() / 2, (uint16_t *)(m_compressedData + m_compressedDataUsed), compressedDataFree() / 2, outpuProcessed); + inputProcessed *= 2; + outpuProcessed *= 2; + if (outpuProcessed < pageDataFree()) { + m_pageDataUsed = SPI_FLASH_PageSize - outpuProcessed; + // TODO: To avoid this copy, use a circular buffer + memmove(m_pageData + m_pageDataUsed, m_pageData, outpuProcessed); + } + + m_compressedDataUsed += inputProcessed; + } + #else + loadPage(m_pageData); + m_pageDataUsed = 0; + m_currentPage++; + #endif +} + +uint16_t SPIFlashStorage::inData(uint8_t* data, uint16_t size) { + // Don't write more than we can + NOMORE(size, pageDataFree()); + memcpy(m_pageData + m_pageDataUsed, data, size); + m_pageDataUsed += size; + return size; +} + +void SPIFlashStorage::writeData(uint8_t* data, uint16_t size) { + // Flush a page if needed + if (pageDataFree() == 0) flushPage(); + + while (size > 0) { + uint16_t written = inData(data, size); + size -= written; + // Need to write more? Flush page and continue! + if (size > 0) { + flushPage(); + data += written; + } + } +} + +void SPIFlashStorage::beginRead(uint32_t startAddress) { + m_startAddress = startAddress; + m_currentPage = 0; + // Nothing in memory now + m_pageDataUsed = SPI_FLASH_PageSize; + #if HAS_SPI_FLASH_COMPRESSION + m_compressedDataUsed = sizeof(m_compressedData); + #endif +} + +uint16_t SPIFlashStorage::outData(uint8_t* data, uint16_t size) { + // Don't read more than we have + NOMORE(size, pageDataFree()); + memcpy(data, m_pageData + m_pageDataUsed, size); + m_pageDataUsed += size; + return size; +} + +void SPIFlashStorage::readData(uint8_t* data, uint16_t size) { + // Read a page if needed + if (pageDataFree() == 0) readPage(); + + while (size > 0) { + uint16_t read = outData(data, size); + size -= read; + // Need to write more? Flush page and continue! + if (size > 0) { + readPage(); + data += read; + } + } +} + +SPIFlashStorage SPIFlash; + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h new file mode 100644 index 0000000..98c8067 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/SPIFlashStorage.h @@ -0,0 +1,108 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "../../../../libs/W25Qxx.h" + +#define HAS_SPI_FLASH_COMPRESSION 1 + +/** + * This class manages and optimizes SPI Flash data storage, + * keeping an internal buffer to write and save full SPI flash + * pages as needed. + * + * Since the data is always in the buffer, the class is also + * able to support fast on-the-fly RLE compression/decompression. + * + * In testing with the current LVGL_UI it compacts 2.9MB of icons + * (which have lots of runs) down to 370kB!!! As a result the UI + * refresh rate becomes faster and now all LVGL UI can fit into a + * tiny 2MB SPI Flash, such as the Chitu Board. + * + * == Usage == + * + * Writing: + * + * The class keeps an internal buffer that caches data until it + * fits into a full SPI Flash page. Each time the buffer fills up + * the page is saved to SPI Flash. Sequential writes are optimal. + * + * SPIFlashStorage.beginWrite(myStartAddress); + * while (there is data to write) + * SPIFlashStorage.addData(myBuffer, bufferSize); + * SPIFlashStorage.endWrite(); // Flush remaining buffer data + * + * Reading: + * + * When reading, it loads a full page from SPI Flash at once and + * keeps it in a private SRAM buffer. Data is loaded as needed to + * fullfill requests. Sequential reads are optimal. + * + * SPIFlashStorage.beginRead(myStartAddress); + * while (there is data to read) + * SPIFlashStorage.readData(myBuffer, bufferSize); + * + * Compression: + * + * The biggest advantage of this class is the RLE compression. + * With compression activated a second buffer holds the compressed + * data, so when writing data, as this buffer becomes full it is + * flushed to SPI Flash. + * + * The same goes for reading: A compressed page is read from SPI + * flash, and the data is uncompressed as needed to provide the + * requested amount of data. + */ +class SPIFlashStorage { +public: + // Write operation + static void beginWrite(uint32_t startAddress); + static void endWrite(); + static void writeData(uint8_t* data, uint16_t size); + + // Read operation + static void beginRead(uint32_t startAddress); + static void readData(uint8_t* data, uint16_t size); + + static uint32_t getCurrentPage() { return m_currentPage; } + +private: + static void flushPage(); + static void savePage(uint8_t* buffer); + static void loadPage(uint8_t* buffer); + static void readPage(); + static uint16_t inData(uint8_t* data, uint16_t size); + static uint16_t outData(uint8_t* data, uint16_t size); + + static uint8_t m_pageData[SPI_FLASH_PageSize]; + static uint32_t m_currentPage; + static uint16_t m_pageDataUsed; + static inline uint16_t pageDataFree() { return SPI_FLASH_PageSize - m_pageDataUsed; } + static uint32_t m_startAddress; + #if HAS_SPI_FLASH_COMPRESSION + static uint8_t m_compressedData[SPI_FLASH_PageSize]; + static uint16_t m_compressedDataUsed; + static inline uint16_t compressedDataFree() { return SPI_FLASH_PageSize - m_compressedDataUsed; } + #endif +}; + +extern SPIFlashStorage SPIFlash; diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.cpp b/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.cpp new file mode 100644 index 0000000..242944b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.cpp @@ -0,0 +1,83 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "SPI_TFT.h" +#include "pic_manager.h" +#include "tft_lvgl_configuration.h" + +#include "../../../../inc/MarlinConfig.h" + +#include <SPI.h> + +#include "draw_ui.h" + +TFT SPI_TFT; + +// use SPI1 for the spi tft. +void TFT::spi_init(uint8_t spiRate) { + tftio.Init(); +} + +void TFT::SetPoint(uint16_t x, uint16_t y, uint16_t point) { + if ((x > 480) || (y > 320)) return; + + setWindow(x, y, 1, 1); + tftio.WriteMultiple(point, (uint16_t)1); +} + +void TFT::setWindow(uint16_t x, uint16_t y, uint16_t with, uint16_t height) { + tftio.set_window(x, y, (x + with - 1), (y + height - 1)); +} + +void TFT::LCD_init() { + tftio.InitTFT(); + #if PIN_EXISTS(TFT_BACKLIGHT) + OUT_WRITE(TFT_BACKLIGHT_PIN, LOW); + #endif + delay(100); + LCD_clear(0x0000); + LCD_Draw_Logo(); + #if PIN_EXISTS(TFT_BACKLIGHT) + OUT_WRITE(TFT_BACKLIGHT_PIN, HIGH); + #endif +} + +void TFT::LCD_clear(uint16_t color) { + setWindow(0, 0, (TFT_WIDTH), (TFT_HEIGHT)); + tftio.WriteMultiple(color, (uint32_t)(TFT_WIDTH) * (TFT_HEIGHT)); +} + +void TFT::LCD_Draw_Logo() { + #if HAS_LOGO_IN_FLASH + setWindow(0, 0, TFT_WIDTH, TFT_HEIGHT); + for (uint16_t i = 0; i < (TFT_HEIGHT); i ++) { + Pic_Logo_Read((uint8_t *)"", (uint8_t *)bmp_public_buf, (TFT_WIDTH) * 2); + tftio.WriteSequence((uint16_t *)bmp_public_buf, TFT_WIDTH); + } + #endif +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.h b/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.h new file mode 100644 index 0000000..f3be3dc --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/SPI_TFT.h @@ -0,0 +1,43 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "../../../tft_io/tft_io.h" + +class TFT { +public: + TFT_IO tftio; + void spi_init(uint8_t spiRate); + void SetPoint(uint16_t x, uint16_t y, uint16_t point); + void setWindow(uint16_t x, uint16_t y, uint16_t with, uint16_t height); + void LCD_init(); + void LCD_clear(uint16_t color); + void LCD_Draw_Logo(); +}; + +extern TFT SPI_TFT; + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_about.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_about.cpp new file mode 100644 index 0000000..4634c5a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_about.cpp @@ -0,0 +1,65 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; +static lv_obj_t *fw_type, *board; + +enum { ID_A_RETURN = 1 }; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_A_RETURN: + lv_clear_cur_ui(); + lv_draw_return_ui(); + break; + } +} + +void lv_draw_about(void) { + scr = lv_screen_create(ABOUT_UI); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_A_RETURN); + + fw_type = lv_label_create(scr, "Firmware: Marlin " SHORT_BUILD_VERSION); + lv_obj_align(fw_type, nullptr, LV_ALIGN_CENTER, 0, -20); + + board = lv_label_create(scr, "Board: " BOARD_INFO_NAME); + lv_obj_align(board, nullptr, LV_ALIGN_CENTER, 0, -60); +} + +void lv_clear_about() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_about.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_about.h new file mode 100644 index 0000000..9eae2b0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_about.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_about(void); +extern void lv_clear_about(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.cpp new file mode 100644 index 0000000..9e5dd4f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.cpp @@ -0,0 +1,155 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/planner.h" +#include "../../../../inc/MarlinConfig.h" +#include "../../../../MarlinCore.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_ACCE_RETURN = 1, + ID_ACCE_PRINT, + ID_ACCE_RETRA, + ID_ACCE_TRAVEL, + ID_ACCE_X, + ID_ACCE_Y, + ID_ACCE_Z, + ID_ACCE_E0, + ID_ACCE_E1, + ID_ACCE_UP, + ID_ACCE_DOWN +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_ACCE_RETURN: + uiCfg.para_ui_page = 0; + lv_clear_acceleration_settings(); + lv_draw_return_ui(); + break; + case ID_ACCE_PRINT: + value = PrintAcceleration; + lv_clear_acceleration_settings(); + lv_draw_number_key(); + break; + case ID_ACCE_RETRA: + value = RetractAcceleration; + lv_clear_acceleration_settings(); + lv_draw_number_key(); + break; + case ID_ACCE_TRAVEL: + value = TravelAcceleration; + lv_clear_acceleration_settings(); + lv_draw_number_key(); + break; + case ID_ACCE_X: + value = XAcceleration; + lv_clear_acceleration_settings(); + lv_draw_number_key(); + break; + case ID_ACCE_Y: + value = YAcceleration; + lv_clear_acceleration_settings(); + lv_draw_number_key(); + break; + case ID_ACCE_Z: + value = ZAcceleration; + lv_clear_acceleration_settings(); + lv_draw_number_key(); + break; + case ID_ACCE_E0: + value = E0Acceleration; + lv_clear_acceleration_settings(); + lv_draw_number_key(); + break; + case ID_ACCE_E1: + value = E1Acceleration; + lv_clear_acceleration_settings(); + lv_draw_number_key(); + break; + case ID_ACCE_UP: + uiCfg.para_ui_page = 0; + lv_clear_acceleration_settings(); + lv_draw_acceleration_settings(); + break; + case ID_ACCE_DOWN: + uiCfg.para_ui_page = 1; + lv_clear_acceleration_settings(); + lv_draw_acceleration_settings(); + break; + } +} + +void lv_draw_acceleration_settings(void) { + scr = lv_screen_create(ACCELERATION_UI, machine_menu.AccelerationConfTitle); + char str_1[16]; + if (uiCfg.para_ui_page != 1) { + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.acceleration, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.PrintAcceleration, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_ACCE_PRINT, 0, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.retract_acceleration, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.RetractAcceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_ACCE_RETRA, 1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.travel_acceleration, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.TravelAcceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_ACCE_TRAVEL, 2, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[X_AXIS]); + lv_screen_menu_item_1_edit(scr, machine_menu.X_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_ACCE_X, 3, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_ACCE_DOWN); + } + else { + sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[Y_AXIS]); + lv_screen_menu_item_1_edit(scr, machine_menu.Y_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_ACCE_Y, 0, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[Z_AXIS]); + lv_screen_menu_item_1_edit(scr, machine_menu.Z_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_ACCE_Z, 1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[E_AXIS]); + lv_screen_menu_item_1_edit(scr, machine_menu.E0_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_ACCE_E0, 2, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)]); + lv_screen_menu_item_1_edit(scr, machine_menu.E1_Acceleration, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_ACCE_E1, 3, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_ACCE_UP); + } + + lv_screen_menu_item_return(scr, event_handler, ID_ACCE_RETURN); +} + +void lv_clear_acceleration_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.h new file mode 100644 index 0000000..6ab4971 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_acceleration_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_acceleration_settings(void); +extern void lv_clear_acceleration_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.cpp new file mode 100644 index 0000000..973fa10 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.cpp @@ -0,0 +1,96 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_ADVANCE_RETURN = 1, + ID_PAUSE_POS, + ID_WIFI_PARA, + ID_FILAMENT_SETTINGS, + ID_ENCODER_SETTINGS +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_ADVANCE_RETURN: + lv_clear_advance_settings(); + lv_draw_return_ui(); + break; + case ID_PAUSE_POS: + lv_clear_advance_settings(); + lv_draw_pause_position(); + break; + case ID_FILAMENT_SETTINGS: + lv_clear_advance_settings(); + lv_draw_filament_settings(); + break; + #if ENABLED(MKS_WIFI_MODULE) + case ID_WIFI_PARA: + lv_clear_advance_settings(); + lv_draw_wifi_settings(); + break; + #endif + #if HAS_ROTARY_ENCODER + case ID_ENCODER_SETTINGS: + lv_clear_advance_settings(); + lv_draw_encoder_settings(); + break; + #endif + } +} + +void lv_draw_advance_settings(void) { + scr = lv_screen_create(ADVANCED_UI, machine_menu.AdvancedConfTitle); + + int index = 0; + lv_screen_menu_item(scr, machine_menu.PausePosition, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_PAUSE_POS, index++); + lv_screen_menu_item(scr, machine_menu.FilamentConf, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_FILAMENT_SETTINGS, index++); + #if ENABLED(MKS_WIFI_MODULE) + lv_screen_menu_item(scr, machine_menu.WifiSettings, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_WIFI_PARA, index++); + #endif + #if HAS_ROTARY_ENCODER + lv_screen_menu_item(scr, machine_menu.EncoderSettings, PARA_UI_POS_X, PARA_UI_POS_Y * (index + 1), event_handler, ID_ENCODER_SETTINGS, index); + index++; + #endif + + lv_screen_menu_item_return(scr, event_handler, ID_ADVANCE_RETURN); +} + +void lv_clear_advance_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.h new file mode 100644 index 0000000..84e4a4d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_advance_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_advance_settings(void); +extern void lv_clear_advance_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.cpp new file mode 100644 index 0000000..0f2a527 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.cpp @@ -0,0 +1,90 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if BOTH(HAS_TFT_LVGL_UI, HAS_BED_PROBE) + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/probe.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_OFFSET_RETURN = 1, + ID_OFFSET_X, + ID_OFFSET_Y, + ID_OFFSET_Z +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_OFFSET_RETURN: + lv_clear_auto_level_offset_settings(); + lv_draw_return_ui(); + break; + case ID_OFFSET_X: + value = x_offset; + lv_clear_auto_level_offset_settings(); + lv_draw_number_key(); + break; + case ID_OFFSET_Y: + value = y_offset; + lv_clear_auto_level_offset_settings(); + lv_draw_number_key(); + break; + case ID_OFFSET_Z: + value = z_offset; + lv_clear_auto_level_offset_settings(); + lv_draw_number_key(); + break; + } +} + +void lv_draw_auto_level_offset_settings(void) { + char str_1[16]; + scr = lv_screen_create(NOZZLE_PROBE_OFFSET_UI, machine_menu.OffsetConfTitle); + + sprintf_P(public_buf_l, PSTR("%s"), TERN(HAS_PROBE_XY_OFFSET,dtostrf(probe.offset.x, 1, 3, str_1) , 0)); + lv_screen_menu_item_1_edit(scr, machine_menu.Xoffset, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_OFFSET_X, 0, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), TERN(HAS_PROBE_XY_OFFSET,dtostrf(probe.offset.y, 1, 3, str_1) , 0)); + lv_screen_menu_item_1_edit(scr, machine_menu.Yoffset, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_OFFSET_Y, 1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), TERN(HAS_PROBE_XY_OFFSET,dtostrf(probe.offset.z, 1, 3, str_1) , 0)); + lv_screen_menu_item_1_edit(scr, machine_menu.Zoffset, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_OFFSET_Z, 2, public_buf_l); + + lv_screen_menu_item_return(scr, event_handler, ID_OFFSET_RETURN); +} + +void lv_clear_auto_level_offset_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI && HAS_BED_PROBE diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.h new file mode 100644 index 0000000..688cd20 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_auto_level_offset_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_auto_level_offset_settings(void); +extern void lv_clear_auto_level_offset_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.cpp new file mode 100644 index 0000000..a94d1c1 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.cpp @@ -0,0 +1,179 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../gcode/queue.h" +#include "../../../../gcode/gcode.h" +#include "../../../../inc/MarlinConfig.h" + +#if ENABLED(EEPROM_SETTINGS) + #include "../../../../module/settings.h" +#endif + +#if HAS_BED_PROBE + #include "../../../../module/probe.h" +#endif + +extern lv_group_t *g; +static lv_obj_t *scr; + +static lv_obj_t *labelV, *buttonV, *zOffsetText; + +enum { + ID_BABY_STEP_X_P = 1, + ID_BABY_STEP_X_N, + ID_BABY_STEP_Y_P, + ID_BABY_STEP_Y_N, + ID_BABY_STEP_Z_P, + ID_BABY_STEP_Z_N, + ID_BABY_STEP_DIST, + ID_BABY_STEP_RETURN +}; + +static float babystep_dist=0.01; +static uint8_t has_adjust_z = 0; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + char baby_buf[30] = { 0 }; + char str_1[16]; + switch (obj->mks_obj_id) { + case ID_BABY_STEP_X_P: + sprintf_P(baby_buf, PSTR("M290 X%s"), dtostrf(babystep_dist, 1, 3, str_1)); + gcode.process_subcommands_now_P(PSTR(baby_buf)); + has_adjust_z = 1; + break; + case ID_BABY_STEP_X_N: + sprintf_P(baby_buf, PSTR("M290 X%s"), dtostrf(-babystep_dist, 1, 3, str_1)); + gcode.process_subcommands_now_P(PSTR(baby_buf)); + has_adjust_z = 1; + break; + case ID_BABY_STEP_Y_P: + sprintf_P(baby_buf, PSTR("M290 Y%s"), dtostrf(babystep_dist, 1, 3, str_1)); + gcode.process_subcommands_now_P(PSTR(baby_buf)); + has_adjust_z = 1; + break; + case ID_BABY_STEP_Y_N: + sprintf_P(baby_buf, PSTR("M290 Y%s"), dtostrf(-babystep_dist, 1, 3, str_1)); + gcode.process_subcommands_now_P(PSTR(baby_buf)); + has_adjust_z = 1; + break; + case ID_BABY_STEP_Z_P: + sprintf_P(baby_buf, PSTR("M290 Z%s"), dtostrf(babystep_dist, 1, 3, str_1)); + gcode.process_subcommands_now_P(PSTR(baby_buf)); + has_adjust_z = 1; + break; + case ID_BABY_STEP_Z_N: + sprintf_P(baby_buf, PSTR("M290 Z%s"), dtostrf(-babystep_dist, 1, 3, str_1)); + gcode.process_subcommands_now_P(PSTR(baby_buf)); + has_adjust_z = 1; + break; + case ID_BABY_STEP_DIST: + if (abs((int)(100 * babystep_dist)) == 1) + babystep_dist = 0.05; + else if (abs((int)(100 * babystep_dist)) == 5) + babystep_dist = 0.1; + else + babystep_dist = 0.01; + disp_baby_step_dist(); + break; + case ID_BABY_STEP_RETURN: + if (has_adjust_z == 1) { + TERN_(EEPROM_SETTINGS, (void)settings.save()); + has_adjust_z = 0; + } + lv_clear_cur_ui(); + lv_draw_return_ui(); + break; + } +} + +void lv_draw_baby_stepping(void) { + scr = lv_screen_create(BABY_STEP_UI); + lv_big_button_create(scr, "F:/bmp_xAdd.bin", move_menu.x_add, INTERVAL_V, titleHeight, event_handler, ID_BABY_STEP_X_P); + lv_big_button_create(scr, "F:/bmp_xDec.bin", move_menu.x_dec, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABY_STEP_X_N); + lv_big_button_create(scr, "F:/bmp_yAdd.bin", move_menu.y_add, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_BABY_STEP_Y_P); + lv_big_button_create(scr, "F:/bmp_yDec.bin", move_menu.y_dec, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABY_STEP_Y_N); + lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_BABY_STEP_Z_P); + lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABY_STEP_Z_N); + buttonV = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_BABY_STEP_DIST); + labelV = lv_label_create_empty(buttonV); + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonV); + } + #endif + + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BABY_STEP_RETURN); + + disp_baby_step_dist(); + + zOffsetText = lv_label_create(scr, 290, TITLE_YPOS, nullptr); + disp_z_offset_value(); +} + +void disp_baby_step_dist() { + if ((int)(100 * babystep_dist) == 1) + lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_01.bin"); + else if ((int)(100 * babystep_dist) == 5) + lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_05.bin"); + else if ((int)(100 * babystep_dist) == 10) + lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_1.bin"); + + if (gCfgItems.multiple_language) { + if ((int)(100 * babystep_dist) == 1) { + lv_label_set_text(labelV, move_menu.step_001mm); + lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if ((int)(100 * babystep_dist) == 5) { + lv_label_set_text(labelV, move_menu.step_005mm); + lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if ((int)(100 * babystep_dist) == 10) { + lv_label_set_text(labelV, move_menu.step_01mm); + lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void disp_z_offset_value() { + char buf[20]; + #if HAS_BED_PROBE + char str_1[16]; + #endif + sprintf_P(buf, PSTR("offset Z: %s mm"), TERN(HAS_BED_PROBE, dtostrf(probe.offset.z, 1, 3, str_1), "0")); + lv_label_set_text(zOffsetText, buf); +} + +void lv_clear_baby_stepping() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.h new file mode 100644 index 0000000..5886a20 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_baby_stepping.h @@ -0,0 +1,35 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_baby_stepping(void); +extern void lv_clear_baby_stepping(); +extern void disp_baby_step_dist(); +extern void disp_z_offset_value(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.cpp new file mode 100644 index 0000000..7fec704 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.cpp @@ -0,0 +1,184 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "../../../../MarlinCore.h" +#include "draw_ui.h" + +#include "../../../../module/temperature.h" +#include "../../../../gcode/queue.h" +#include "../../../../gcode/gcode.h" + +#include "../../../../module/probe.h" + +extern lv_group_t *g; +static lv_obj_t *scr, *labelV, *buttonV, *zOffsetText; +static lv_obj_t *labelExt1, *labelBed; + +static uint8_t has_adjust_z = 0; +static float step_dist=0.01; + +enum { + ID_BLTOUCH_INIT = 1, + ID_BLTOUCH_ZOFFSETPOS, + ID_BLTOUCH_ZOFFSETNEG, + ID_BLTOUCH_SAVE, + ID_BLTOUCH_TEST, + ID_BLTOUCH_STEPS, + ID_BLTOUCH_RETURN + }; + + +static void event_handler(lv_obj_t * obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + char baby_buf[30] = { 0 }; + char str_1[40]; + switch (obj->mks_obj_id) { + case ID_BLTOUCH_INIT: + bltouch_do_init(); + break; + case ID_BLTOUCH_ZOFFSETPOS: + sprintf_P(baby_buf, PSTR("M290 Z%s"), dtostrf(step_dist, 1, 3, str_1)); + gcode.process_subcommands_now_P(PSTR(baby_buf)); + has_adjust_z = 1; + break; + case ID_BLTOUCH_ZOFFSETNEG: + sprintf_P(baby_buf, PSTR("M290 Z%s"), dtostrf(-step_dist, 1, 3, str_1)); + gcode.process_subcommands_now_P(PSTR(baby_buf)); + has_adjust_z = 1; + break; + case ID_BLTOUCH_SAVE: + if (queue.length <= (BUFSIZE - 2)) queue.enqueue_now_P(PSTR("M500\nG28 X Y")); + + break; + case ID_BLTOUCH_TEST: + sprintf_P(str_1, PSTR("G28\nG1 Z10 F2400\nG1 X%d Y%d\nG1 Z0"), X_MAX_POS / 2, Y_MAX_POS / 2); + if (!queue.length) queue.enqueue_now_P(PSTR(str_1)); + break; + case ID_BLTOUCH_STEPS: + if (abs((int)(100 * step_dist)) == 1) + step_dist = 0.05; + else if (abs((int)(100 * step_dist)) == 5) + step_dist = 0.1; + else + step_dist = 0.01; + disp_step_dist(); + break; + case ID_BLTOUCH_RETURN: + TERN_(HAS_SOFTWARE_ENDSTOPS, soft_endstop._enabled = true); + lv_clear_bltouch_settings(); + lv_draw_return_ui(); + break; + + } +} + +void lv_draw_bltouch_settings(void) { + scr = lv_screen_create(BLTOUCH_UI, machine_menu.BLTouchLevelingConfTitle); + // Create image buttons + lv_big_button_create(scr, "F:/bmp_Add.bin" , machine_menu.BLTouchOffsetpos, INTERVAL_V, titleHeight, event_handler, ID_BLTOUCH_ZOFFSETPOS); + lv_obj_t *buttonExt1 = lv_img_create(scr, nullptr); + lv_img_set_src(buttonExt1 , "F:/bmp_ext1_state.bin"); + lv_obj_set_pos(buttonExt1 , 171, 50); + + lv_obj_t *buttonBedstate = lv_img_create(scr, nullptr); + lv_img_set_src(buttonBedstate, "F:/bmp_bed_state.bin"); + lv_obj_set_pos(buttonBedstate, 266, 50); + labelExt1 = lv_label_create(scr, 161, 115, nullptr); + labelBed = lv_label_create(scr, 256, 115, nullptr); + + lv_obj_align(labelExt1, buttonExt1 , LV_ALIGN_IN_BOTTOM_MID, 2, 20); + lv_obj_align(labelBed , buttonBedstate, LV_ALIGN_IN_BOTTOM_MID, 2, 20); + + zOffsetText = lv_label_create(scr , 170, 140, nullptr); + lv_big_button_create(scr, "F:/bmp_Dec.bin" , machine_menu.BLTouchOffsetneg, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_BLTOUCH_ZOFFSETNEG); + + buttonV = lv_imgbtn_create(scr , nullptr , INTERVAL_V , BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BLTOUCH_STEPS); + labelV = lv_label_create_empty(buttonV); + + lv_big_button_create(scr, "F:/bmp_in.bin" , machine_menu.BLTouchTest , BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BLTOUCH_TEST); + lv_big_button_create(scr, "F:/bmp_set.bin" , machine_menu.BLTouchSave , BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BLTOUCH_SAVE); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back , BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_BLTOUCH_RETURN); + + disp_step_dist(); + disp_bltouch_z_offset_value(); +} + +void disp_step_dist() { + if ((int)(100 * step_dist) == 1) + lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_01.bin"); + else if ((int)(100 * step_dist) == 5) + lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_05.bin"); + else if ((int)(100 * step_dist) == 10) + lv_imgbtn_set_src_both(buttonV, "F:/bmp_baby_move0_1.bin"); + + if (gCfgItems.multiple_language) { + if ((int)(100 * step_dist) == 1) { + lv_label_set_text(labelV, move_menu.step_001mm); + lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if ((int)(100 * step_dist) == 5) { + lv_label_set_text(labelV, move_menu.step_005mm); + lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if ((int)(100 * step_dist) == 10) { + lv_label_set_text(labelV, move_menu.step_01mm); + lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void disp_bltouch_z_offset_value() { + char buf[20]; + char str_1[16]; + sprintf_P(buf, PSTR("Z Offset : %s mm"), dtostrf(probe.offset.z, 1, 2, str_1) ); + lv_label_set_text(zOffsetText, buf); + + sprintf(public_buf_l, printing_menu.temp1, (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target); + lv_label_set_text(labelExt1, public_buf_l); + + #if HAS_HEATED_BED + sprintf(public_buf_l, printing_menu.bed_temp, (int)thermalManager.temp_bed.celsius, (int)thermalManager.temp_bed.target); + lv_label_set_text(labelBed, public_buf_l); + #endif + +} + +void bltouch_do_init() { + char str_1[50]; + TERN_(HAS_BED_PROBE, probe.offset.z = 0); + TERN_(HAS_SOFTWARE_ENDSTOPS, soft_endstop._enabled = false); + queue.clear(); + sprintf_P(str_1, PSTR("G28\nG1 Z10 F2400\nG1 X%d Y%d\nG1 Z0"), X_MAX_POS / 2, Y_MAX_POS / 2); + queue.enqueue_now_P(PSTR(str_1)); +} + +void lv_clear_bltouch_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.h new file mode 100644 index 0000000..5f33359 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_bltouch_settings.h @@ -0,0 +1,37 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus +extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_bltouch_settings(void); +extern void lv_clear_bltouch_settings(); +extern void disp_step_dist(); +extern void bltouch_do_init(); +extern void disp_bltouch_z_offset_value(); + +//extern void disp_temp_ready_print(); +#ifdef __cplusplus +} /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.cpp new file mode 100644 index 0000000..bb3be74 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.cpp @@ -0,0 +1,225 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/planner.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; +static lv_obj_t *labelStep, *buttonStep, *buttonMov, *buttonExt; +static lv_obj_t *labelMov, *labelExt; +static lv_obj_t *printSpeedText; + +enum { + ID_C_ADD = 1, + ID_C_DEC, + ID_C_MOVE, + ID_C_EXT, + ID_C_STEP, + ID_C_RETURN +}; + +static bool editingFlowrate; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_C_ADD: + if (!editingFlowrate) { + if (feedrate_percentage < MAX_EXT_SPEED_PERCENT - uiCfg.stepPrintSpeed) + feedrate_percentage += uiCfg.stepPrintSpeed; + else + feedrate_percentage = MAX_EXT_SPEED_PERCENT; + } + else { + if (planner.flow_percentage[0] < MAX_EXT_SPEED_PERCENT - uiCfg.stepPrintSpeed) + planner.flow_percentage[0] += uiCfg.stepPrintSpeed; + else + planner.flow_percentage[0] = MAX_EXT_SPEED_PERCENT; + planner.refresh_e_factor(0); + #if HAS_MULTI_EXTRUDER + planner.flow_percentage[1] = planner.flow_percentage[0]; + planner.refresh_e_factor(1); + #endif + } + disp_print_speed(); + break; + case ID_C_DEC: + if (!editingFlowrate) { + if (feedrate_percentage > MIN_EXT_SPEED_PERCENT + uiCfg.stepPrintSpeed) + feedrate_percentage -= uiCfg.stepPrintSpeed; + else + feedrate_percentage = MIN_EXT_SPEED_PERCENT; + } + else { + if (planner.flow_percentage[0] > MIN_EXT_SPEED_PERCENT + uiCfg.stepPrintSpeed) + planner.flow_percentage[0] -= uiCfg.stepPrintSpeed; + else + planner.flow_percentage[0] = MIN_EXT_SPEED_PERCENT; + planner.refresh_e_factor(0); + #if HAS_MULTI_EXTRUDER + planner.flow_percentage[1] = planner.flow_percentage[0]; + planner.refresh_e_factor(1); + #endif + } + disp_print_speed(); + break; + case ID_C_MOVE: + editingFlowrate = false; + disp_speed_type(); + disp_print_speed(); + break; + case ID_C_EXT: + editingFlowrate = true; + disp_speed_type(); + disp_print_speed(); + break; + case ID_C_STEP: + if (uiCfg.stepPrintSpeed == 1) + uiCfg.stepPrintSpeed = 5; + else if (uiCfg.stepPrintSpeed == 5) + uiCfg.stepPrintSpeed = 10; + else + uiCfg.stepPrintSpeed = 1; + disp_speed_step(); + break; + case ID_C_RETURN: + lv_clear_cur_ui(); + lv_draw_return_ui(); + break; + } +} + +void lv_draw_change_speed(void) { + scr = lv_screen_create(CHANGE_SPEED_UI); + // Create an Image button + lv_big_button_create(scr, "F:/bmp_Add.bin", speed_menu.add, INTERVAL_V, titleHeight, event_handler, ID_C_ADD); + lv_big_button_create(scr, "F:/bmp_Dec.bin", speed_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_C_DEC); + buttonMov = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_MOVE); + buttonExt = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_EXT); + buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_STEP); + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonMov); + lv_group_add_obj(g, buttonExt); + lv_group_add_obj(g, buttonStep); + } + #endif + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_C_RETURN); + + // Create labels on the image buttons + labelMov = lv_label_create_empty(buttonMov); + labelExt = lv_label_create_empty(buttonExt); + labelStep = lv_label_create_empty(buttonStep); + + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonMov); + lv_group_add_obj(g, buttonExt); + lv_group_add_obj(g, buttonStep); + } + #endif + + disp_speed_type(); + disp_speed_step(); + + printSpeedText = lv_label_create_empty(scr); + lv_obj_set_style(printSpeedText, &tft_style_label_rel); + disp_print_speed(); +} + +void disp_speed_step() { + if (uiCfg.stepPrintSpeed == 1) + lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step1_percent.bin"); + else if (uiCfg.stepPrintSpeed == 5) + lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step5_percent.bin"); + else if (uiCfg.stepPrintSpeed == 10) + lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step10_percent.bin"); + + if (gCfgItems.multiple_language) { + if (uiCfg.stepPrintSpeed == 1) { + lv_label_set_text(labelStep, speed_menu.step_1percent); + lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if (uiCfg.stepPrintSpeed == 5) { + lv_label_set_text(labelStep, speed_menu.step_5percent); + lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if (uiCfg.stepPrintSpeed == 10) { + lv_label_set_text(labelStep, speed_menu.step_10percent); + lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void disp_print_speed() { + char buf[30] = { 0 }; + + public_buf_l[0] = '\0'; + + int16_t val; + const char *lbl; + if (editingFlowrate) { + lbl = speed_menu.extrude_speed; + val = planner.flow_percentage[0]; + } + else { + lbl = speed_menu.move_speed; + val = feedrate_percentage; + } + strcpy(public_buf_l, lbl); + strcat_P(public_buf_l, PSTR(": ")); + sprintf_P(buf, PSTR("%d%%"), val); + strcat(public_buf_l, buf); + lv_label_set_text(printSpeedText, public_buf_l); + lv_obj_align(printSpeedText, nullptr, LV_ALIGN_CENTER, 0, -65); +} + +void disp_speed_type() { + lv_imgbtn_set_src_both(buttonMov, editingFlowrate ? "F:/bmp_mov_changeSpeed.bin" : "F:/bmp_mov_sel.bin"); + lv_imgbtn_set_src_both(buttonExt, editingFlowrate ? "F:/bmp_extruct_sel.bin" : "F:/bmp_speed_extruct.bin"); + lv_obj_refresh_ext_draw_pad(buttonExt); + lv_obj_refresh_ext_draw_pad(buttonMov); + + if (gCfgItems.multiple_language) { + lv_label_set_text(labelMov, speed_menu.move); + lv_obj_align(labelMov, buttonMov, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + + lv_label_set_text(labelExt, speed_menu.extrude); + lv_obj_align(labelExt, buttonExt, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } +} + +void lv_clear_change_speed() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.h new file mode 100644 index 0000000..8fa4c80 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_change_speed.h @@ -0,0 +1,39 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +#define MIN_EXT_SPEED_PERCENT 10 +#define MAX_EXT_SPEED_PERCENT 999 + +extern void lv_draw_change_speed(void); +extern void lv_clear_change_speed(); +extern void disp_speed_step(); +extern void disp_print_speed(); +extern void disp_speed_type(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.cpp new file mode 100644 index 0000000..38c3ebf --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.cpp @@ -0,0 +1,205 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if BOTH(HAS_TFT_LVGL_UI, MKS_WIFI_MODULE) + +#include "lv_conf.h" +#include "draw_ui.h" + +#include "../../../../MarlinCore.h" +#include "../../../../module/temperature.h" + +#include "QR_Encode.h" + +extern lv_group_t * g; +static lv_obj_t * scr; +static lv_obj_t *button_bind_or_not = NULL, *label_bind_or_not = NULL; +static lv_obj_t *buttonReleaseBind = NULL, *label_ReleaseBind = NULL; +static lv_obj_t * text_id; + +static uint8_t unbinding_flag = 0; +static uint8_t id_mark = 0; + +#define ID_CLOUD_BIND_RETURN 1 +#define ID_CLOUD_BIND_OR_NOT 2 +#define ID_CLOUD_RELEASE_BIND 3 + +static void event_handler(lv_obj_t * obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_CLOUD_BIND_RETURN: + lv_clear_cur_ui(); + lv_draw_return_ui(); + break; + case ID_CLOUD_RELEASE_BIND: + if (cloud_para.state == 0x12) { + lv_clear_cur_ui(); + lv_draw_dialog(DIALOG_TYPE_UNBIND); + } + break; + } +} + +void lv_draw_cloud_bind(void) { + lv_obj_t *buttonBack = NULL, *label_Back = NULL; + scr = lv_screen_create(BIND_UI); + + button_bind_or_not = lv_btn_create(scr, NULL); + lv_obj_set_pos(button_bind_or_not, TFT_WIDTH - 130, TFT_HEIGHT - 80 * 3); + lv_obj_set_size(button_bind_or_not, PARA_UI_VALUE_BTN_X_SIZE + 15, PARA_UI_VALUE_BTN_Y_SIZE + 15); + lv_obj_set_event_cb_mks(button_bind_or_not, event_handler, ID_CLOUD_BIND_OR_NOT, NULL, 0); + lv_btn_set_style(button_bind_or_not, LV_BTN_STYLE_REL, &style_para_value); + lv_btn_set_style(button_bind_or_not, LV_BTN_STYLE_PR, &style_para_value); + label_bind_or_not = lv_label_create_empty(button_bind_or_not); + + buttonReleaseBind = lv_btn_create(scr, NULL); + lv_obj_set_pos(buttonReleaseBind, TFT_WIDTH - 130, TFT_HEIGHT - 80 * 2); + lv_obj_set_size(buttonReleaseBind, PARA_UI_VALUE_BTN_X_SIZE + 15, PARA_UI_VALUE_BTN_Y_SIZE + 15); + lv_obj_set_event_cb_mks(buttonReleaseBind, event_handler, ID_CLOUD_RELEASE_BIND, NULL, 0); + label_ReleaseBind = lv_label_create_empty(buttonReleaseBind); + lv_label_set_text(label_ReleaseBind, cloud_menu.unbind); + lv_obj_align(label_ReleaseBind, buttonReleaseBind, LV_ALIGN_CENTER, 0, 0); + + buttonBack = lv_btn_create(scr, NULL); + lv_obj_set_pos(buttonBack, TFT_WIDTH - 130, TFT_HEIGHT - 80); + lv_obj_set_size(buttonBack, PARA_UI_VALUE_BTN_X_SIZE + 15, PARA_UI_VALUE_BTN_Y_SIZE + 15); + lv_obj_set_event_cb_mks(buttonBack, event_handler, ID_CLOUD_BIND_RETURN, NULL, 0); + lv_btn_set_style(buttonBack, LV_BTN_STYLE_REL, &style_para_back); + lv_btn_set_style(buttonBack, LV_BTN_STYLE_PR, &style_para_back); + label_Back = lv_label_create_empty(buttonBack); + lv_label_set_text(label_Back, common_menu.text_back); + lv_obj_align(label_Back, buttonBack, LV_ALIGN_CENTER, 0, 0); + + #if BUTTONS_EXIST(EN1, EN2, ENC) + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonReleaseBind); + lv_group_add_obj(g, buttonBack); + } + #endif + + text_id = lv_label_create_empty(scr); + lv_obj_set_pos(text_id, 50, 60 + 200 + 20); + lv_obj_set_style(text_id, &tft_style_label_rel); + lv_label_set_text(text_id, (char *)cloud_para.id); + + id_mark = 0; + + disp_bind_state(); +} + +void disp_bind_state() { + if (cloud_para.state != 0x12) + unbinding_flag = 0; + + if (unbinding_flag) { + lv_label_set_text(label_bind_or_not, cloud_menu.unbinding); + lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0); + lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_REL, &style_para_value); + lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_PR, &style_para_value); + } + else { + if (cloud_para.state == 0x10) { + lv_label_set_text(label_bind_or_not, cloud_menu.disconnected); + lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0); + } + else if (cloud_para.state == 0x11) { + lv_label_set_text(label_bind_or_not, cloud_menu.unbinded); + lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0); + } + else if (cloud_para.state == 0x12) { + lv_label_set_text(label_bind_or_not, cloud_menu.binded); + lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0); + } + else { + lv_label_set_text(label_bind_or_not, cloud_menu.disable); + lv_obj_align(label_bind_or_not, button_bind_or_not, LV_ALIGN_CENTER, 0, 0); + } + } + + if (cloud_para.state == 0x12 && !unbinding_flag) { + lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_REL, &style_para_back); + lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_PR, &style_para_back); + } + else { + lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_REL, &style_para_value); + lv_btn_set_style(buttonReleaseBind, LV_BTN_STYLE_PR, &style_para_value); + } +} + +static char last_cloud_state = 0; +void refresh_bind_ui() { + if ((last_cloud_state != cloud_para.state) || unbinding_flag) { + disp_bind_state(); + last_cloud_state = cloud_para.state; + } + if (cloud_para.id[0]) { + if (!id_mark) { + display_qrcode((uint8_t *)cloud_para.id); + lv_label_set_text(text_id, (char *)cloud_para.id); + } + } + else + id_mark = 0; +} + +void display_qrcode(uint8_t *qrcode_data) { + uint8_t i, j; + uint16_t x, y, p; + + if (!id_mark) { + EncodeData((char *)qrcode_data); + id_mark = 1; + } + + lv_fill_rect(10, QRCODE_Y, 300, QRCODE_Y + 300, LV_COLOR_WHITE); + + if (m_nSymbleSize * 2 > QRCODE_WIDTH) return; + + for (i = 0; i < 40; i++) + if ((m_nSymbleSize * i * 2) > QRCODE_WIDTH) break; + + p = (i - 1) * 2; + + x = QRCODE_X + 70; + y = QRCODE_Y + 70; + + for (i = 0; i < m_nSymbleSize; i++) + for (j = 0; j < m_nSymbleSize; j++) + if (m_byModuleData[i][j] == 1) + lv_fill_rect(x + p * i, y + p * j, x + p * (i + 1) - 1, y + p * (j + 1) - 1, LV_COLOR_BACKGROUND); +} + +void cloud_unbind() { + package_to_wifi(WIFI_CLOUD_UNBIND, (uint8_t *)0, 0); + unbinding_flag = 1; +} + +void lv_clear_cloud_bind() { + #if BUTTONS_EXIST(EN1, EN2, ENC) + if (gCfgItems.encoder_enable) + lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.h new file mode 100644 index 0000000..f0f354a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_cloud_bind.h @@ -0,0 +1,37 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus +extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_cloud_bind(void); +extern void lv_clear_cloud_bind(); +extern void disp_bind_state(); +extern void refresh_bind_ui(); +extern void display_qrcode(uint8_t *qrcode_data); +extern void cloud_unbind(); + +#ifdef __cplusplus +} /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp new file mode 100644 index 0000000..4b0eebe --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.cpp @@ -0,0 +1,574 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/** + * draw_dialog.cpp + */ + +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../sd/cardreader.h" +#include "../../../../gcode/queue.h" +#include "../../../../module/temperature.h" +#include "../../../../module/planner.h" +#include "../../../../gcode/gcode.h" +#include "../../../../inc/MarlinConfig.h" + +#if ENABLED(EEPROM_SETTINGS) + #include "../../../../module/settings.h" +#endif + +#if ENABLED(POWER_LOSS_RECOVERY) + #include "../../../../feature/powerloss.h" +#endif + +#if ENABLED(PARK_HEAD_ON_PAUSE) + #include "../../../../feature/pause.h" +#endif + +#if ENABLED(TOUCH_SCREEN_CALIBRATION) + #include "../../../tft_io/touch_calibration.h" + #include "draw_touch_calibration.h" +#endif + +extern lv_group_t *g; +static lv_obj_t *scr, *tempText1, *filament_bar; + +extern uint8_t sel_id; +extern bool once_flag, gcode_preview_over; +extern int upload_result; +extern uint32_t upload_time; +extern uint32_t upload_size; +extern bool temps_update_flag; + +static void btn_ok_event_cb(lv_obj_t *btn, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + if (DIALOG_IS(TYPE_PRINT_FILE)) { + #if HAS_GCODE_PREVIEW + preview_gcode_prehandle(list_file.file_name[sel_id]); + #endif + reset_print_time(); + start_print_time(); + + uiCfg.print_state = WORKING; + lv_clear_dialog(); + lv_draw_printing(); + + #if ENABLED(SDSUPPORT) + if (!gcode_preview_over) { + //char *cur_name; + //cur_name = strrchr(list_file.file_name[sel_id], '/'); + + //SdFile file, *curDir; + card.endFilePrint(); + //const char * const fname = card.diveToFile(true, curDir, cur_name); + //if (!fname) return; + //if (file.open(curDir, fname, O_READ)) { + //gCfgItems.curFilesize = file.fileSize(); + //file.close(); + //update_spi_flash(); + //} + card.openFileRead(list_file.file_name[sel_id]); + if (card.isFileOpen()) { + gCfgItems.curFilesize = card.getFileSize(); + update_spi_flash(); + feedrate_percentage = 100; + planner.flow_percentage[0] = 100; + planner.e_factor[0] = planner.flow_percentage[0] * 0.01f; + #if HAS_MULTI_EXTRUDER + planner.flow_percentage[1] = 100; + planner.e_factor[1] = planner.flow_percentage[1] * 0.01f; + #endif + card.startFileprint(); + #if ENABLED(POWER_LOSS_RECOVERY) + recovery.prepare(); + #endif + once_flag = false; + } + } + #endif + } + else if (DIALOG_IS(TYPE_STOP)) { + wait_for_heatup = false; + stop_print_time(); + lv_clear_dialog(); + lv_draw_ready_print(); + + #if ENABLED(SDSUPPORT) + uiCfg.print_state = IDLE; + card.flag.abort_sd_printing = true; + #endif + } + else if (DIALOG_IS(TYPE_FINISH_PRINT)) { + lv_clear_cur_ui(); + lv_draw_ready_print(); + } + #if ENABLED(ADVANCED_PAUSE_FEATURE) + else if (DIALOG_IS(PAUSE_MESSAGE_WAITING, PAUSE_MESSAGE_INSERT, PAUSE_MESSAGE_HEAT)) + wait_for_user = false; + else if (DIALOG_IS(PAUSE_MESSAGE_OPTION)) + pause_menu_response = PAUSE_RESPONSE_EXTRUDE_MORE; + else if (DIALOG_IS(PAUSE_MESSAGE_RESUME)) { + lv_clear_cur_ui(); + lv_draw_return_ui(); + } + #endif + else if (DIALOG_IS(STORE_EEPROM_TIPS)) { + TERN_(EEPROM_SETTINGS, (void)settings.save()); + lv_clear_cur_ui(); + lv_draw_return_ui(); + } + else if (DIALOG_IS(READ_EEPROM_TIPS)) { + TERN_(EEPROM_SETTINGS, (void)settings.load()); + lv_clear_cur_ui(); + lv_draw_return_ui(); + } + else if (DIALOG_IS(REVERT_EEPROM_TIPS)) { + TERN_(EEPROM_SETTINGS, (void)settings.reset()); + lv_clear_cur_ui(); + #if ENABLED(TOUCH_SCREEN_CALIBRATION) + const bool do_draw_cal = touch_calibration.need_calibration(); + if (do_draw_cal) { + disp_state_stack._disp_index--; // We are asynchronous from the dialog, so let's remove the dialog from the stack + lv_draw_touch_calibration_screen(); + } + #else + constexpr bool do_draw_cal = false; + #endif + if (!do_draw_cal) lv_draw_return_ui(); + } + else if (DIALOG_IS(WIFI_CONFIG_TIPS)) { + uiCfg.configWifi = 1; + lv_clear_cur_ui(); + lv_draw_return_ui(); + } + else if (DIALOG_IS(TYPE_FILAMENT_HEAT_LOAD_COMPLETED)) + uiCfg.filament_heat_completed_load = 1; + else if (DIALOG_IS(TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED)) + uiCfg.filament_heat_completed_unload = 1; + else if (DIALOG_IS(TYPE_FILAMENT_LOAD_COMPLETED, TYPE_FILAMENT_UNLOAD_COMPLETED)) { + lv_clear_cur_ui(); + lv_draw_return_ui(); + } + #if ENABLED(MKS_WIFI_MODULE) + else if (DIALOG_IS(TYPE_UNBIND)) { + cloud_unbind(); + lv_clear_cur_ui(); + lv_draw_return_ui(); + } + #endif + else { + lv_clear_cur_ui(); + lv_draw_return_ui(); + } +} + +static void btn_cancel_event_cb(lv_obj_t *btn, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + if (DIALOG_IS(PAUSE_MESSAGE_OPTION)) { + TERN_(ADVANCED_PAUSE_FEATURE, pause_menu_response = PAUSE_RESPONSE_RESUME_PRINT); + } + else if (DIALOG_IS(TYPE_FILAMENT_LOAD_HEAT, TYPE_FILAMENT_UNLOAD_HEAT, TYPE_FILAMENT_HEAT_LOAD_COMPLETED, TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED)) { + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target= uiCfg.desireSprayerTempBak; + thermalManager.start_watching_hotend(uiCfg.curSprayerChoose); + lv_clear_cur_ui(); + lv_draw_return_ui(); + } + else if (DIALOG_IS(TYPE_FILAMENT_LOADING, TYPE_FILAMENT_UNLOADING)) { + queue.enqueue_one_P(PSTR("M410")); + uiCfg.filament_rate = 0; + uiCfg.filament_loading_completed = 0; + uiCfg.filament_unloading_completed = 0; + uiCfg.filament_loading_time_flg = 0; + uiCfg.filament_loading_time_cnt = 0; + uiCfg.filament_unloading_time_flg = 0; + uiCfg.filament_unloading_time_cnt = 0; + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = uiCfg.desireSprayerTempBak; + thermalManager.start_watching_hotend(uiCfg.curSprayerChoose); + lv_clear_cur_ui(); + lv_draw_return_ui(); + } + else { + lv_clear_cur_ui(); + lv_draw_return_ui(); + } +} + +void lv_draw_dialog(uint8_t type) { + lv_obj_t *btnOk = nullptr, *btnCancel = nullptr; + uiCfg.dialogType = type; + scr = lv_screen_create(DIALOG_UI); + + lv_obj_t *labelDialog = lv_label_create(scr, ""); + + if (DIALOG_IS(TYPE_FINISH_PRINT, PAUSE_MESSAGE_RESUME)) { + btnOk = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_ok_event_cb); + lv_obj_t *labelOk = lv_label_create_empty(btnOk); // Add a label to the button + lv_label_set_text(labelOk, print_file_dialog_menu.confirm); // Set the labels text + } + else if (DIALOG_IS(PAUSE_MESSAGE_WAITING, PAUSE_MESSAGE_INSERT, PAUSE_MESSAGE_HEAT)) { + btnOk = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_ok_event_cb); + lv_obj_t *labelOk = lv_label_create_empty(btnOk); // Add a label to the button + lv_label_set_text(labelOk, print_file_dialog_menu.confirm); // Set the labels text + } + else if (DIALOG_IS(PAUSE_MESSAGE_PAUSING, PAUSE_MESSAGE_CHANGING, PAUSE_MESSAGE_UNLOAD, PAUSE_MESSAGE_LOAD, PAUSE_MESSAGE_PURGE, PAUSE_MESSAGE_RESUME, PAUSE_MESSAGE_HEATING)) { + // nothing to do + } + else if (DIALOG_IS(WIFI_ENABLE_TIPS)) { + btnCancel = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_cancel_event_cb); + lv_obj_t *labelCancel = lv_label_create_empty(btnCancel); + lv_label_set_text(labelCancel, print_file_dialog_menu.cancel); + } + else if (DIALOG_IS(TRANSFER_NO_DEVICE)) { + btnCancel = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_cancel_event_cb); + lv_obj_t *labelCancel = lv_label_create_empty(btnCancel); + lv_label_set_text(labelCancel, print_file_dialog_menu.cancel); + } + #if ENABLED(MKS_WIFI_MODULE) + else if (DIALOG_IS(TYPE_UPLOAD_FILE)) { + if (upload_result == 2) { + btnCancel = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_cancel_event_cb); + lv_obj_t *labelCancel = lv_label_create_empty(btnCancel); + lv_label_set_text(labelCancel, print_file_dialog_menu.cancel); + } + else if (upload_result == 3) { + btnOk = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_ok_event_cb); + lv_obj_t *labelOk = lv_label_create_empty(btnOk); + lv_label_set_text(labelOk, print_file_dialog_menu.confirm); + } + } + else if (DIALOG_IS(TYPE_UPDATE_ESP_FIRMARE)) { + // nothing to do + } + #endif + else if (DIALOG_IS(TYPE_FILAMENT_LOAD_HEAT, TYPE_FILAMENT_UNLOAD_HEAT)) { + btnCancel = lv_button_btn_create(scr, BTN_OK_X+90, BTN_OK_Y, 100, 50, btn_cancel_event_cb); + lv_obj_t *labelCancel = lv_label_create_empty(btnCancel); + lv_label_set_text(labelCancel, print_file_dialog_menu.cancel); + + tempText1 = lv_label_create_empty(scr); + filament_sprayer_temp(); + } + else if (DIALOG_IS(TYPE_FILAMENT_LOAD_COMPLETED, TYPE_FILAMENT_UNLOAD_COMPLETED)) { + btnOk = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_ok_event_cb); + lv_obj_t *labelOk = lv_label_create_empty(btnOk); + lv_label_set_text(labelOk, print_file_dialog_menu.confirm); + } + else if (DIALOG_IS(TYPE_FILAMENT_LOADING, TYPE_FILAMENT_UNLOADING)) { + btnCancel = lv_button_btn_create(scr, BTN_OK_X + 90, BTN_OK_Y, 100, 50, btn_cancel_event_cb); + lv_obj_t *labelCancel = lv_label_create_empty(btnCancel); + lv_label_set_text(labelCancel, print_file_dialog_menu.cancel); + + filament_bar = lv_bar_create(scr, nullptr); + lv_obj_set_pos(filament_bar, (TFT_WIDTH-400)/2, ((TFT_HEIGHT - titleHeight)-40)/2); + lv_obj_set_size(filament_bar, 400, 25); + lv_bar_set_style(filament_bar, LV_BAR_STYLE_INDIC, &lv_bar_style_indic); + lv_bar_set_anim_time(filament_bar, 1000); + lv_bar_set_value(filament_bar, 0, LV_ANIM_ON); + } + else if(DIALOG_IS(TYPE_MACHINE_PAUSING_TIPS)) { + //nothing to do + } + else { + btnOk = lv_button_btn_create(scr, BTN_OK_X, BTN_OK_Y, 100, 50, btn_ok_event_cb); + lv_obj_t *labelOk = lv_label_create_empty(btnOk); // Add a label to the button + + btnCancel = lv_button_btn_create(scr, BTN_CANCEL_X, BTN_CANCEL_Y, 100, 50, btn_cancel_event_cb); + lv_obj_t *labelCancel = lv_label_create_empty(btnCancel); // Add a label to the button + + if (DIALOG_IS(PAUSE_MESSAGE_OPTION)) { + lv_label_set_text(labelOk, pause_msg_menu.purgeMore); // Set the labels text + lv_label_set_text(labelCancel, pause_msg_menu.continuePrint); + } + else { + lv_label_set_text(labelOk, print_file_dialog_menu.confirm); // Set the labels text + lv_label_set_text(labelCancel, print_file_dialog_menu.cancel); + } + } + if (DIALOG_IS(TYPE_PRINT_FILE)) { + lv_label_set_text(labelDialog, print_file_dialog_menu.print_file); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + + lv_obj_t *labelFile = lv_label_create(scr, list_file.long_name[sel_id]); + lv_obj_align(labelFile, nullptr, LV_ALIGN_CENTER, 0, -60); + } + else if (DIALOG_IS(TYPE_STOP)) { + lv_label_set_text(labelDialog, print_file_dialog_menu.cancel_print); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(TYPE_FINISH_PRINT)) { + lv_label_set_text(labelDialog, print_file_dialog_menu.print_finish); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_PAUSING)) { + lv_label_set_text(labelDialog, pause_msg_menu.pausing); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_CHANGING)) { + lv_label_set_text(labelDialog, pause_msg_menu.changing); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_UNLOAD)) { + lv_label_set_text(labelDialog, pause_msg_menu.unload); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_WAITING)) { + lv_label_set_text(labelDialog, pause_msg_menu.waiting); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_INSERT)) { + lv_label_set_text(labelDialog, pause_msg_menu.insert); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_LOAD)) { + lv_label_set_text(labelDialog, pause_msg_menu.load); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_PURGE)) { + lv_label_set_text(labelDialog, pause_msg_menu.purge); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_RESUME)) { + lv_label_set_text(labelDialog, pause_msg_menu.resume); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_HEAT)) { + lv_label_set_text(labelDialog, pause_msg_menu.heat); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_HEATING)) { + lv_label_set_text(labelDialog, pause_msg_menu.heating); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(PAUSE_MESSAGE_OPTION)) { + lv_label_set_text(labelDialog, pause_msg_menu.option); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(STORE_EEPROM_TIPS)) { + lv_label_set_text(labelDialog, eeprom_menu.storeTips); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(READ_EEPROM_TIPS)) { + lv_label_set_text(labelDialog, eeprom_menu.readTips); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(REVERT_EEPROM_TIPS)) { + lv_label_set_text(labelDialog, eeprom_menu.revertTips); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(WIFI_CONFIG_TIPS)) { + lv_label_set_text(labelDialog, machine_menu.wifiConfigTips); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(WIFI_ENABLE_TIPS)) { + lv_label_set_text(labelDialog, print_file_dialog_menu.wifi_enable_tips); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(TRANSFER_NO_DEVICE)) { + lv_label_set_text(labelDialog, DIALOG_UPDATE_NO_DEVICE_EN); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + #if ENABLED(MKS_WIFI_MODULE) + else if (DIALOG_IS(TYPE_UPLOAD_FILE)) { + if (upload_result == 1) { + lv_label_set_text(labelDialog, DIALOG_UPLOAD_ING_EN); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (upload_result == 2) { + lv_label_set_text(labelDialog, DIALOG_UPLOAD_ERROR_EN); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (upload_result == 3) { + char buf[200]; + int _index = 0; + + strcpy(buf, DIALOG_UPLOAD_FINISH_EN); + _index = strlen(buf); + buf[_index] = '\n'; + _index++; + strcat(buf, DIALOG_UPLOAD_SIZE_EN); + + _index = strlen(buf); + buf[_index] = ':'; + _index++; + sprintf(&buf[_index], " %d KBytes\n", (int)(upload_size / 1024)); + + strcat(buf, DIALOG_UPLOAD_TIME_EN); + _index = strlen(buf); + buf[_index] = ':'; + _index++; + sprintf(&buf[_index], " %d s\n", (int)upload_time); + + strcat(buf, DIALOG_UPLOAD_SPEED_EN); + _index = strlen(buf); + buf[_index] = ':'; + _index++; + sprintf(&buf[_index], " %d KBytes/s\n", (int)(upload_size / upload_time / 1024)); + + lv_label_set_text(labelDialog, buf); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + } + else if (DIALOG_IS(TYPE_UPDATE_ESP_FIRMARE)) { + lv_label_set_text(labelDialog, DIALOG_UPDATE_WIFI_FIRMWARE_EN); + lv_obj_align(labelDialog, NULL, LV_ALIGN_CENTER, 0, -20); + } + #endif // MKS_WIFI_MODULE + else if (DIALOG_IS(TYPE_FILAMENT_LOAD_HEAT)) { + lv_label_set_text(labelDialog, filament_menu.filament_dialog_load_heat); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(TYPE_FILAMENT_HEAT_LOAD_COMPLETED)) { + lv_label_set_text(labelDialog, filament_menu.filament_dialog_load_heat_confirm); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(TYPE_FILAMENT_UNLOAD_HEAT)) { + lv_label_set_text(labelDialog, filament_menu.filament_dialog_unload_heat); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED)) { + lv_label_set_text(labelDialog, filament_menu.filament_dialog_unload_heat_confirm); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(TYPE_FILAMENT_LOAD_COMPLETED)) { + lv_label_set_text(labelDialog, filament_menu.filament_dialog_load_completed); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(TYPE_FILAMENT_UNLOAD_COMPLETED)) { + lv_label_set_text(labelDialog, filament_menu.filament_dialog_unload_completed); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -20); + } + else if (DIALOG_IS(TYPE_FILAMENT_LOADING)) { + lv_label_set_text(labelDialog, filament_menu.filament_dialog_loading); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -70); + } + else if (DIALOG_IS(TYPE_FILAMENT_UNLOADING)) { + lv_label_set_text(labelDialog, filament_menu.filament_dialog_unloading); + lv_obj_align(labelDialog, nullptr, LV_ALIGN_CENTER, 0, -70); + } + #if ENABLED(MKS_WIFI_MODULE) + else if (DIALOG_IS(TYPE_UNBIND)) { + lv_label_set_text(labelDialog, common_menu.unbind_printer_tips); + lv_obj_align(labelDialog, NULL, LV_ALIGN_CENTER, 0, -70); + } + #endif + else if(DIALOG_IS(TYPE_MACHINE_PAUSING_TIPS)) { + lv_label_set_text(labelDialog, print_file_dialog_menu.machinePausingTips); + lv_obj_align(labelDialog, NULL, LV_ALIGN_CENTER, 0, 0); + } + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + if (btnOk) lv_group_add_obj(g, btnOk); + if (btnCancel) lv_group_add_obj(g, btnCancel); + } + #endif +} + +void filament_sprayer_temp() { + char buf[20] = {0}; + sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target); + + strcpy(public_buf_l, uiCfg.curSprayerChoose < 1 ? extrude_menu.ext1 : extrude_menu.ext2); + strcat_P(public_buf_l, PSTR(": ")); + strcat(public_buf_l, buf); + lv_label_set_text(tempText1, public_buf_l); + lv_obj_align(tempText1, nullptr, LV_ALIGN_CENTER, 0, -50); +} + +void filament_dialog_handle() { + if (temps_update_flag && (DIALOG_IS(TYPE_FILAMENT_LOAD_HEAT, TYPE_FILAMENT_UNLOAD_HEAT))) { + filament_sprayer_temp(); + temps_update_flag = false; + } + if (uiCfg.filament_heat_completed_load == 1) { + uiCfg.filament_heat_completed_load = 0; + lv_clear_dialog(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_LOADING); + planner.synchronize(); + uiCfg.filament_loading_time_flg = 1; + uiCfg.filament_loading_time_cnt = 0; + sprintf_P(public_buf_m, PSTR("T%d\nG91\nG1 E%d F%d\nG90"), uiCfg.curSprayerChoose, gCfgItems.filamentchange_load_length, gCfgItems.filamentchange_load_speed); + queue.inject(public_buf_m); + } + if (uiCfg.filament_heat_completed_unload == 1) { + uiCfg.filament_heat_completed_unload = 0; + lv_clear_dialog(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_UNLOADING); + planner.synchronize(); + uiCfg.filament_unloading_time_flg = 1; + uiCfg.filament_unloading_time_cnt = 0; + sprintf_P(public_buf_m, PSTR("T%d\nG91\nG1 E-%d F%d\nG90"), uiCfg.curSprayerChoose, gCfgItems.filamentchange_unload_length, gCfgItems.filamentchange_unload_speed); + queue.inject(public_buf_m); + } + + if (((abs((int)((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius - gCfgItems.filament_limit_temper)) <= 1) + || ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius > gCfgItems.filament_limit_temper)) + && (uiCfg.filament_load_heat_flg == 1) + ) { + uiCfg.filament_load_heat_flg = 0; + lv_clear_dialog(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_LOAD_COMPLETED); + } + + if (uiCfg.filament_loading_completed == 1) { + uiCfg.filament_rate = 0; + uiCfg.filament_loading_completed = 0; + lv_clear_dialog(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_LOAD_COMPLETED); + } + if (((abs((int)((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius - gCfgItems.filament_limit_temper)) <= 1) + || ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius > gCfgItems.filament_limit_temper)) + && (uiCfg.filament_unload_heat_flg == 1) + ) { + uiCfg.filament_unload_heat_flg = 0; + lv_clear_dialog(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED); + } + + if (uiCfg.filament_unloading_completed == 1) { + uiCfg.filament_rate = 0; + uiCfg.filament_unloading_completed = 0; + lv_clear_dialog(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_UNLOAD_COMPLETED); + } + + if (DIALOG_IS(TYPE_FILAMENT_LOADING, TYPE_FILAMENT_UNLOADING)) + lv_filament_setbar(); +} + +void lv_filament_setbar() { + lv_bar_set_value(filament_bar, uiCfg.filament_rate, LV_ANIM_ON); +} + +void lv_clear_dialog() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.h new file mode 100644 index 0000000..69b8491 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_dialog.h @@ -0,0 +1,91 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +enum { + DIALOG_TYPE_STOP = 0, + DIALOG_TYPE_PRINT_FILE, + DIALOG_TYPE_REPRINT_NO_FILE, + + DIALOG_TYPE_M80_FAIL, + DIALOG_TYPE_MESSAGE_ERR1, + + DIALOG_TYPE_UPDATE_ESP_FIRMARE, + DIALOG_TYPE_UPDATE_ESP_DATA, + DIALOG_TYPE_UPLOAD_FILE, + DIALOG_TYPE_UNBIND, + + DIALOG_TYPE_FILAMENT_LOAD_HEAT, + DIALOG_TYPE_FILAMENT_HEAT_LOAD_COMPLETED, + DIALOG_TYPE_FILAMENT_LOADING, + DIALOG_TYPE_FILAMENT_LOAD_COMPLETED, + DIALOG_TYPE_FILAMENT_UNLOAD_HEAT, + DIALOG_TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED, + DIALOG_TYPE_FILAMENT_UNLOADING, + DIALOG_TYPE_FILAMENT_UNLOAD_COMPLETED, + + DIALOG_TYPE_FILE_LOADING, + + DIALOG_TYPE_FILAMENT_NO_PRESS, + DIALOG_TYPE_FINISH_PRINT, + + DIALOG_WIFI_ENABLE_TIPS, + + DIALOG_PAUSE_MESSAGE_PAUSING, + DIALOG_PAUSE_MESSAGE_CHANGING, + DIALOG_PAUSE_MESSAGE_UNLOAD, + DIALOG_PAUSE_MESSAGE_WAITING, + DIALOG_PAUSE_MESSAGE_INSERT, + DIALOG_PAUSE_MESSAGE_LOAD, + DIALOG_PAUSE_MESSAGE_PURGE, + DIALOG_PAUSE_MESSAGE_RESUME, + DIALOG_PAUSE_MESSAGE_HEAT, + DIALOG_PAUSE_MESSAGE_HEATING, + DIALOG_PAUSE_MESSAGE_OPTION, + + DIALOG_STORE_EEPROM_TIPS, + DIALOG_READ_EEPROM_TIPS, + DIALOG_REVERT_EEPROM_TIPS, + + DIALOG_WIFI_CONFIG_TIPS, + DIALOG_TRANSFER_NO_DEVICE, + DIALOG_TYPE_MACHINE_PAUSING_TIPS +}; + +#define BTN_OK_X 100 +#define BTN_OK_Y 180 +#define BTN_CANCEL_X 280 +#define BTN_CANCEL_Y 180 + +extern void lv_draw_dialog(uint8_t type); +extern void lv_clear_dialog(); +extern void filament_sprayer_temp(); +extern void filament_dialog_handle(); +extern void lv_filament_setbar(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.cpp new file mode 100644 index 0000000..446b942 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.cpp @@ -0,0 +1,82 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_EEPROM_RETURN = 1, + ID_EEPROM_STORE, + ID_EEPROM_STORE_ARROW, + ID_EEPROM_READ, + ID_EEPROM_READ_ARROW, + ID_EEPROM_REVERT, + ID_EEPROM_REVERT_ARROW +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_EEPROM_RETURN: + lv_clear_eeprom_settings(); + lv_draw_return_ui(); + break; + case ID_EEPROM_STORE: + lv_clear_eeprom_settings(); + lv_draw_dialog(DIALOG_STORE_EEPROM_TIPS); + break; + #if 0 + case ID_EEPROM_READ: + lv_clear_eeprom_settings(); + lv_draw_dialog(DIALOG_READ_EEPROM_TIPS); + break; + #endif + case ID_EEPROM_REVERT: + lv_clear_eeprom_settings(); + lv_draw_dialog(DIALOG_REVERT_EEPROM_TIPS); + break; + } +} + +void lv_draw_eeprom_settings(void) { + scr = lv_screen_create(EEPROM_SETTINGS_UI); + lv_screen_menu_item(scr, eeprom_menu.revert, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_EEPROM_REVERT, 0); + lv_screen_menu_item(scr, eeprom_menu.store, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_EEPROM_STORE, 1); + lv_screen_menu_item_return(scr, event_handler, ID_EEPROM_RETURN); +} + +void lv_clear_eeprom_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.h new file mode 100644 index 0000000..6d5ecf0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_eeprom_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_eeprom_settings(void); +extern void lv_clear_eeprom_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.cpp new file mode 100644 index 0000000..ab48924 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.cpp @@ -0,0 +1,72 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +#if BUTTONS_EXIST(EN1, EN2) + +extern lv_group_t *g; +static lv_obj_t *scr; +static lv_obj_t *buttonEncoderState = nullptr; + +enum { + ID_ENCODER_RETURN = 1, + ID_ENCODER_STATE +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_ENCODER_RETURN: + lv_clear_encoder_settings(); + lv_draw_return_ui(); + break; + case ID_ENCODER_STATE: + gCfgItems.encoder_enable ^= true; + lv_screen_menu_item_onoff_update(buttonEncoderState, gCfgItems.encoder_enable); + update_spi_flash(); + break; + } +} + +void lv_draw_encoder_settings(void) { + scr = lv_screen_create(ENCODER_SETTINGS_UI, machine_menu.EncoderConfTitle); + buttonEncoderState = lv_screen_menu_item_onoff(scr, machine_menu.EncoderConfText, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_ENCODER_STATE, 0, gCfgItems.encoder_enable); + lv_screen_menu_item_return(scr, event_handler, ID_ENCODER_RETURN); +} + +void lv_clear_encoder_settings() { + #if HAS_ROTARY_ENCODER + lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // BUTTONS_EXIST(EN1, EN2) + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.h new file mode 100644 index 0000000..62892a6 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_encoder_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_encoder_settings(void); +extern void lv_clear_encoder_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.cpp new file mode 100644 index 0000000..bdae725 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.cpp @@ -0,0 +1,46 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "tft_lvgl_configuration.h" + +#include "SPI_TFT.h" +#include "mks_hardware_test.h" +#include "../../../../inc/MarlinConfig.h" + +static lv_obj_t *scr; + +void lv_draw_error_message(PGM_P const msg) { + SPI_TFT.LCD_clear(0x0000); + if (msg) disp_string((TFT_WIDTH - strlen(msg) * 16) / 2, 100, msg, 0xFFFF, 0x0000); + disp_string((TFT_WIDTH - strlen("PRINTER HALTED") * 16) / 2, 140, "PRINTER HALTED", 0xFFFF, 0x0000); + disp_string((TFT_WIDTH - strlen("Please Reset") * 16) / 2, 180, "Please Reset", 0xFFFF, 0x0000); +} + +void lv_clear_error_message() { lv_obj_del(scr); } + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.h new file mode 100644 index 0000000..35e3bd6 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_error_message.h @@ -0,0 +1,37 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +#ifndef PGM_P + #define PGM_P const char * +#endif + +extern void lv_draw_error_message(PGM_P const msg); +extern void lv_clear_error_message(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.cpp new file mode 100644 index 0000000..d3574d2 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.cpp @@ -0,0 +1,266 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/temperature.h" +#include "../../../../gcode/queue.h" +#include "../../../../inc/MarlinConfig.h" +#include "../../../../module/planner.h" + +static lv_obj_t *scr; +extern lv_group_t *g; +static lv_obj_t *buttonType, *buttonStep, *buttonSpeed; +static lv_obj_t *labelType; +static lv_obj_t *labelStep; +static lv_obj_t *labelSpeed; +static lv_obj_t *tempText; +static lv_obj_t *ExtruText; + +enum { + ID_E_ADD = 1, + ID_E_DEC, + ID_E_TYPE, + ID_E_STEP, + ID_E_SPEED, + ID_E_RETURN +}; + +static int32_t extrudeAmount; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_E_ADD: + if (thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius >= EXTRUDE_MINTEMP) { + queue.enqueue_now_P(PSTR("G91")); + sprintf_P((char *)public_buf_l, PSTR("G1 E%d F%d"), uiCfg.extruStep, 60 * uiCfg.extruSpeed); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G90")); + extrudeAmount += uiCfg.extruStep; + disp_extru_amount(); + } + break; + case ID_E_DEC: + if (thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius >= EXTRUDE_MINTEMP) { + queue.enqueue_now_P(PSTR("G91")); + sprintf_P((char *)public_buf_l, PSTR("G1 E%d F%d"), 0 - uiCfg.extruStep, 60 * uiCfg.extruSpeed); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G90")); + extrudeAmount -= uiCfg.extruStep; + disp_extru_amount(); + } + break; + case ID_E_TYPE: + if (ENABLED(HAS_MULTI_EXTRUDER)) { + if (uiCfg.curSprayerChoose == 0) { + uiCfg.curSprayerChoose = 1; + queue.inject_P(PSTR("T1")); + } + else { + uiCfg.curSprayerChoose = 0; + queue.inject_P(PSTR("T0")); + } + } + else + uiCfg.curSprayerChoose = 0; + + extrudeAmount = 0; + disp_hotend_temp(); + disp_ext_type(); + disp_extru_amount(); + break; + case ID_E_STEP: + switch (abs(uiCfg.extruStep)) { + case 1: uiCfg.extruStep = 5; break; + case 5: uiCfg.extruStep = 10; break; + case 10: uiCfg.extruStep = 1; break; + default: break; + } + disp_ext_step(); + break; + case ID_E_SPEED: + switch (uiCfg.extruSpeed) { + case 1: uiCfg.extruSpeed = 10; break; + case 10: uiCfg.extruSpeed = 20; break; + case 20: uiCfg.extruSpeed = 1; break; + default: break; + } + disp_ext_speed(); + break; + case ID_E_RETURN: + feedrate_mm_s = (float)uiCfg.moveSpeed_bak; + if(uiCfg.print_state == PAUSED) + planner.set_e_position_mm((destination.e = current_position.e = uiCfg.current_e_position_bak)); + lv_clear_cur_ui(); + lv_draw_return_ui(); + break; + } +} + +void lv_draw_extrusion(void) { + scr = lv_screen_create(EXTRUSION_UI); + // Create image buttons + lv_obj_t *buttonAdd = lv_big_button_create(scr, "F:/bmp_in.bin", extrude_menu.in, INTERVAL_V, titleHeight, event_handler, ID_E_ADD); + lv_obj_clear_protect(buttonAdd, LV_PROTECT_FOLLOW); + lv_big_button_create(scr, "F:/bmp_out.bin", extrude_menu.out, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_E_DEC); + + buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_TYPE); + buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_STEP); + buttonSpeed = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_SPEED); + + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonType); + lv_group_add_obj(g, buttonStep); + lv_group_add_obj(g, buttonSpeed); + } + #endif + + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_E_RETURN); + + // Create labels on the image buttons + labelType = lv_label_create_empty(buttonType); + labelStep = lv_label_create_empty(buttonStep); + labelSpeed = lv_label_create_empty(buttonSpeed); + + disp_ext_type(); + disp_ext_step(); + disp_ext_speed(); + + tempText = lv_label_create_empty(scr); + lv_obj_set_style(tempText, &tft_style_label_rel); + disp_hotend_temp(); + + ExtruText = lv_label_create_empty(scr); + lv_obj_set_style(ExtruText, &tft_style_label_rel); + disp_extru_amount(); +} + +void disp_ext_type() { + if (uiCfg.curSprayerChoose == 1) { + lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru2.bin"); + if (gCfgItems.multiple_language) { + lv_label_set_text(labelType, extrude_menu.ext2); + lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } + else { + lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru1.bin"); + if (gCfgItems.multiple_language) { + lv_label_set_text(labelType, extrude_menu.ext1); + lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void disp_ext_speed() { + if (uiCfg.extruSpeed == 20) + lv_imgbtn_set_src_both(buttonSpeed, "F:/bmp_speed_high.bin"); + else if (uiCfg.extruSpeed == 1) + lv_imgbtn_set_src_both(buttonSpeed, "F:/bmp_speed_slow.bin"); + else + lv_imgbtn_set_src_both(buttonSpeed, "F:/bmp_speed_normal.bin"); + + if (gCfgItems.multiple_language) { + if (uiCfg.extruSpeed == 20) { + lv_label_set_text(labelSpeed, extrude_menu.high); + lv_obj_align(labelSpeed, buttonSpeed, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if (uiCfg.extruSpeed == 1) { + lv_label_set_text(labelSpeed, extrude_menu.low); + lv_obj_align(labelSpeed, buttonSpeed, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else { + lv_label_set_text(labelSpeed, extrude_menu.normal); + lv_obj_align(labelSpeed, buttonSpeed, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void disp_hotend_temp() { + char buf[20] = {0}; + #if ENABLED(SINGLENOZZLE) + sprintf(buf, extrude_menu.temp_value, (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target); + #else + sprintf(buf, extrude_menu.temp_value, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target); + #endif + strcpy(public_buf_l, extrude_menu.temper_text); + strcat(public_buf_l, buf); + lv_label_set_text(tempText, public_buf_l); + lv_obj_align(tempText, nullptr, LV_ALIGN_CENTER, 0, -50); +} + +void disp_extru_amount() { + char buf1[10] = {0}; + + public_buf_l[0] = '\0'; + + if (extrudeAmount < 999 && extrudeAmount > -99) + sprintf(buf1, extrude_menu.count_value_mm, extrudeAmount); + else if (extrudeAmount < 9999 && extrudeAmount > -999) + sprintf(buf1, extrude_menu.count_value_cm, extrudeAmount / 10); + else + sprintf(buf1, extrude_menu.count_value_m, extrudeAmount / 1000); + strcat(public_buf_l, uiCfg.curSprayerChoose < 1 ? extrude_menu.ext1 : extrude_menu.ext2); + strcat(public_buf_l, buf1); + + lv_label_set_text(ExtruText, public_buf_l); + lv_obj_align(ExtruText, nullptr, LV_ALIGN_CENTER, 0, -75); +} + +void disp_ext_step() { + if (uiCfg.extruStep == 1) + lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step1_mm.bin"); + else if (uiCfg.extruStep == 5) + lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step5_mm.bin"); + else if (uiCfg.extruStep == 10) + lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step10_mm.bin"); + + if (gCfgItems.multiple_language) { + if (uiCfg.extruStep == 1) { + lv_label_set_text(labelStep, extrude_menu.step_1mm); + lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if (uiCfg.extruStep == 5) { + lv_label_set_text(labelStep, extrude_menu.step_5mm); + lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if (uiCfg.extruStep == 10) { + lv_label_set_text(labelStep, extrude_menu.step_10mm); + lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void lv_clear_extrusion() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.h new file mode 100644 index 0000000..6178a8e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_extrusion.h @@ -0,0 +1,38 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_extrusion(void); +extern void lv_clear_extrusion(); +extern void disp_ext_type(); +extern void disp_ext_step(); +extern void disp_ext_speed(); +extern void disp_hotend_temp(); +extern void disp_extru_amount(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.cpp new file mode 100644 index 0000000..ae2f432 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.cpp @@ -0,0 +1,117 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/temperature.h" +#include "../../../../gcode/queue.h" +#include "../../../../gcode/gcode.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; +static lv_obj_t *fanText; + +enum { + ID_F_ADD = 1, + ID_F_DEC, + ID_F_HIGH, + ID_F_MID, + ID_F_OFF, + ID_F_RETURN +}; + +static uint8_t fanSpeed; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + + switch (obj->mks_obj_id) { + case ID_F_ADD: + if (fanSpeed < 254) fanSpeed++; + break; + case ID_F_DEC: + if (fanSpeed > 0) fanSpeed--; + break; + case ID_F_HIGH: + fanSpeed = 255; + break; + case ID_F_MID: + fanSpeed = 127; + break; + case ID_F_OFF: + gcode.process_subcommands_now_P(PSTR("M107")); + return; + case ID_F_RETURN: + lv_clear_cur_ui(); + lv_draw_return_ui(); + return; + } + sprintf_P(public_buf_l, PSTR("M106 S%d"), fanSpeed); + gcode.process_subcommands_now(public_buf_l); +} + +void lv_draw_fan(void) { + lv_obj_t *buttonAdd; + + #if HAS_FAN + fanSpeed = thermalManager.fan_speed[0]; + #endif + + scr = lv_screen_create(FAN_UI); + // Create an Image button + buttonAdd = lv_big_button_create(scr, "F:/bmp_Add.bin", fan_menu.add, INTERVAL_V, titleHeight, event_handler, ID_F_ADD); + lv_obj_clear_protect(buttonAdd, LV_PROTECT_FOLLOW); + lv_big_button_create(scr, "F:/bmp_Dec.bin", fan_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_F_DEC); + lv_big_button_create(scr, "F:/bmp_speed255.bin", fan_menu.full, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_HIGH); + lv_big_button_create(scr, "F:/bmp_speed127.bin", fan_menu.half, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_MID); + lv_big_button_create(scr, "F:/bmp_speed0.bin", fan_menu.off, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_OFF); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_F_RETURN); + + fanText = lv_label_create_empty(scr); + lv_obj_set_style(fanText, &tft_style_label_rel); + disp_fan_value(); +} + +void disp_fan_value() { + char buf1[10] = {0}; + public_buf_l[0] = '\0'; + strcat(public_buf_l, fan_menu.state); + strcat_P(public_buf_l, PSTR(": ")); + sprintf_P(buf1, PSTR("%3d"), thermalManager.fan_speed[0]); + strcat(public_buf_l, buf1); + lv_label_set_text(fanText, public_buf_l); + lv_obj_align(fanText, nullptr, LV_ALIGN_CENTER, 0, -65); +} + +void lv_clear_fan() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.h new file mode 100644 index 0000000..5a3323e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_fan.h @@ -0,0 +1,34 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_fan(void); +extern void lv_clear_fan(); +extern void disp_fan_value(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.cpp new file mode 100644 index 0000000..d5bdb3f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.cpp @@ -0,0 +1,216 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/temperature.h" +#include "../../../../gcode/gcode.h" +#include "../../../../module/motion.h" +#include "../../../../module/planner.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; +static lv_obj_t *buttonType; +static lv_obj_t *labelType; +static lv_obj_t *tempText1; + +enum { + ID_FILAMNT_IN = 1, + ID_FILAMNT_OUT, + ID_FILAMNT_TYPE, + ID_FILAMNT_RETURN +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_FILAMNT_IN: + uiCfg.filament_load_heat_flg = 1; + #if ENABLED(SINGLENOZZLE) + if ((abs(thermalManager.temp_hotend[0].target - thermalManager.temp_hotend[0].celsius) <= 1) + || (gCfgItems.filament_limit_temper <= thermalManager.temp_hotend[0].celsius)) { + lv_clear_filament_change(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_LOAD_COMPLETED); + } + else { + lv_clear_filament_change(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_LOAD_HEAT); + if (thermalManager.temp_hotend[0].target < gCfgItems.filament_limit_temper) { + thermalManager.temp_hotend[0].target = gCfgItems.filament_limit_temper; + thermalManager.start_watching_hotend(0); + } + } + #else + if ((abs(thermalManager.temp_hotend[uiCfg.curSprayerChoose].target - thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius) <= 1) + || (gCfgItems.filament_limit_temper <= thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius)) { + lv_clear_filament_change(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_LOAD_COMPLETED); + } + else { + lv_clear_filament_change(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_LOAD_HEAT); + if (thermalManager.temp_hotend[uiCfg.curSprayerChoose].target < gCfgItems.filament_limit_temper) { + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = gCfgItems.filament_limit_temper; + thermalManager.start_watching_hotend(uiCfg.curSprayerChoose); + } + } + #endif + break; + case ID_FILAMNT_OUT: + uiCfg.filament_unload_heat_flg=1; + #if ENABLED(SINGLENOZZLE) + if ((thermalManager.temp_hotend[0].target > 0) + && ((abs((int)((int)thermalManager.temp_hotend[0].target - thermalManager.temp_hotend[0].celsius)) <= 1) + || ((int)thermalManager.temp_hotend[0].celsius >= gCfgItems.filament_limit_temper)) + ) { + lv_clear_filament_change(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED); + } + else { + lv_clear_filament_change(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_UNLOAD_HEAT); + if (thermalManager.temp_hotend[0].target < gCfgItems.filament_limit_temper) { + thermalManager.temp_hotend[0].target = gCfgItems.filament_limit_temper; + thermalManager.start_watching_hotend(0); + } + filament_sprayer_temp(); + } + #else + if ((thermalManager.temp_hotend[uiCfg.curSprayerChoose].target > 0) + && ((abs((int)((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target - thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius)) <= 1) + || ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius >= gCfgItems.filament_limit_temper)) + ) { + lv_clear_filament_change(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_HEAT_UNLOAD_COMPLETED); + } + else { + lv_clear_filament_change(); + lv_draw_dialog(DIALOG_TYPE_FILAMENT_UNLOAD_HEAT); + if (thermalManager.temp_hotend[uiCfg.curSprayerChoose].target < gCfgItems.filament_limit_temper) { + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = gCfgItems.filament_limit_temper; + thermalManager.start_watching_hotend(uiCfg.curSprayerChoose); + } + filament_sprayer_temp(); + } + #endif + break; + case ID_FILAMNT_TYPE: + #if HAS_MULTI_EXTRUDER + uiCfg.curSprayerChoose = !uiCfg.curSprayerChoose; + #endif + disp_filament_type(); + break; + case ID_FILAMNT_RETURN: + #if HAS_MULTI_EXTRUDER + if (uiCfg.print_state != IDLE && uiCfg.print_state != REPRINTED) + gcode.process_subcommands_now_P(uiCfg.curSprayerChoose_bak == 1 ? PSTR("T1") : PSTR("T0")); + #endif + feedrate_mm_s = (float)uiCfg.moveSpeed_bak; + if (uiCfg.print_state == PAUSED) + planner.set_e_position_mm((destination.e = current_position.e = uiCfg.current_e_position_bak)); + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = uiCfg.desireSprayerTempBak; + thermalManager.start_watching_hotend(uiCfg.curSprayerChoose); + + //Reset filament flag + uiCfg.filament_heat_completed_load = 0; + uiCfg.filament_heat_completed_unload = 0; + uiCfg.filament_load_heat_flg = 0; + uiCfg.filament_unload_heat_flg = 0; + uiCfg.filament_loading_completed = 0; + uiCfg.filament_unloading_completed = 0; + + lv_clear_cur_ui(); + lv_draw_return_ui(); + break; + } +} + +void lv_draw_filament_change(void) { + scr = lv_screen_create(FILAMENTCHANGE_UI); + // Create an Image button + lv_obj_t *buttonIn = lv_big_button_create(scr, "F:/bmp_in.bin", filament_menu.in, INTERVAL_V, titleHeight, event_handler, ID_FILAMNT_IN); + lv_obj_clear_protect(buttonIn, LV_PROTECT_FOLLOW); + lv_big_button_create(scr, "F:/bmp_out.bin", filament_menu.out, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_FILAMNT_OUT); + + buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_TYPE); + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonType); + } + #endif + + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FILAMNT_RETURN); + + // Create labels on the image buttons + labelType = lv_label_create_empty(buttonType); + + disp_filament_type(); + + tempText1 = lv_label_create_empty(scr); + lv_obj_set_style(tempText1, &tft_style_label_rel); + disp_filament_temp(); +} + +void disp_filament_type() { + if (uiCfg.curSprayerChoose == 1) { + lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru2.bin"); + if (gCfgItems.multiple_language) { + lv_label_set_text(labelType, preheat_menu.ext2); + lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } + else { + lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru1.bin"); + if (gCfgItems.multiple_language) { + lv_label_set_text(labelType, preheat_menu.ext1); + lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void disp_filament_temp() { + char buf[20] = {0}; + + public_buf_l[0] = '\0'; + + strcat(public_buf_l, uiCfg.curSprayerChoose < 1 ? preheat_menu.ext1 : preheat_menu.ext2); + sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target); + + strcat_P(public_buf_l, PSTR(": ")); + strcat(public_buf_l, buf); + lv_label_set_text(tempText1, public_buf_l); + lv_obj_align(tempText1, nullptr, LV_ALIGN_CENTER, 0, -50); +} + +void lv_clear_filament_change() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.h new file mode 100644 index 0000000..18efe58 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_change.h @@ -0,0 +1,35 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_filament_change(void); +extern void lv_clear_filament_change(); +extern void disp_filament_type(); +extern void disp_filament_temp(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.cpp new file mode 100644 index 0000000..ab87fed --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.cpp @@ -0,0 +1,126 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_FILAMENT_SET_RETURN = 1, + ID_FILAMENT_SET_IN_LENGTH, + ID_FILAMENT_SET_IN_SPEED, + ID_FILAMENT_SET_OUT_LENGTH, + ID_FILAMENT_SET_OUT_SPEED, + ID_FILAMENT_SET_TEMP, + ID_FILAMENT_SET_DOWN, + ID_FILAMENT_SET_UP +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_FILAMENT_SET_RETURN: + uiCfg.para_ui_page = 0; + lv_clear_filament_settings(); + lv_draw_return_ui(); + break; + case ID_FILAMENT_SET_IN_LENGTH: + value = load_length; + lv_clear_filament_settings(); + lv_draw_number_key(); + break; + case ID_FILAMENT_SET_IN_SPEED: + value = load_speed; + lv_clear_filament_settings(); + lv_draw_number_key(); + break; + case ID_FILAMENT_SET_OUT_LENGTH: + value = unload_length; + lv_clear_filament_settings(); + lv_draw_number_key(); + break; + case ID_FILAMENT_SET_OUT_SPEED: + value = unload_speed; + lv_clear_filament_settings(); + lv_draw_number_key(); + break; + case ID_FILAMENT_SET_TEMP: + value = filament_temp; + lv_clear_filament_settings(); + lv_draw_number_key(); + break; + case ID_FILAMENT_SET_UP: + uiCfg.para_ui_page = 0; + lv_clear_filament_settings(); + lv_draw_filament_settings(); + break; + case ID_FILAMENT_SET_DOWN: + uiCfg.para_ui_page = 1; + lv_clear_filament_settings(); + lv_draw_filament_settings(); + break; + } +} + +void lv_draw_filament_settings(void) { + scr = lv_screen_create(FILAMENT_SETTINGS_UI, machine_menu.FilamentConfTitle); + + if (uiCfg.para_ui_page != 1) { + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filamentchange_load_length); + lv_screen_menu_item_1_edit(scr, machine_menu.InLength, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_FILAMENT_SET_IN_LENGTH, 0, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filamentchange_load_speed); + lv_screen_menu_item_1_edit(scr, machine_menu.InSpeed, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_FILAMENT_SET_IN_SPEED, 1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filamentchange_unload_length); + lv_screen_menu_item_1_edit(scr, machine_menu.OutLength, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_FILAMENT_SET_OUT_LENGTH, 2, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filamentchange_unload_speed); + lv_screen_menu_item_1_edit(scr, machine_menu.OutSpeed, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_FILAMENT_SET_OUT_SPEED, 3, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_FILAMENT_SET_DOWN); + } + else { + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.filament_limit_temper); + lv_screen_menu_item_1_edit(scr, machine_menu.FilamentTemperature, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_FILAMENT_SET_TEMP, 0, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_FILAMENT_SET_UP); + } + + lv_screen_menu_item_return(scr, event_handler, ID_FILAMENT_SET_RETURN); +} + +void lv_clear_filament_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.h new file mode 100644 index 0000000..a5ae542 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_filament_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_filament_settings(void); +extern void lv_clear_filament_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp new file mode 100644 index 0000000..1b0a07b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.cpp @@ -0,0 +1,93 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ready_print.h" +#include "draw_set.h" +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../gcode/queue.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_H_ALL = 1, + ID_H_X, + ID_H_Y, + ID_H_Z, + ID_H_RETURN, + ID_H_OFF_ALL, + ID_H_OFF_XY +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_H_ALL: + queue.inject_P(PSTR("G28")); + break; + case ID_H_X: + queue.inject_P(PSTR("G28 X0")); + break; + case ID_H_Y: + queue.inject_P(PSTR("G28 Y0")); + break; + case ID_H_Z: + queue.inject_P(PSTR("G28 Z0")); + break; + case ID_H_OFF_ALL: + queue.inject_P(PSTR("M84")); + break; + case ID_H_OFF_XY: + queue.inject_P(PSTR("M84 X Y")); + break; + case ID_H_RETURN: + lv_clear_cur_ui(); + lv_draw_return_ui(); + break; + } +} + +void lv_draw_home(void) { + scr = lv_screen_create(ZERO_UI); + lv_big_button_create(scr, "F:/bmp_zeroAll.bin", home_menu.home_all, INTERVAL_V, titleHeight, event_handler, ID_H_ALL); + lv_big_button_create(scr, "F:/bmp_zeroX.bin", home_menu.home_x, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_H_X); + lv_big_button_create(scr, "F:/bmp_zeroY.bin", home_menu.home_y, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_H_Y); + lv_big_button_create(scr, "F:/bmp_zeroZ.bin", home_menu.home_z, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_H_Z); + lv_big_button_create(scr, "F:/bmp_function1.bin", set_menu.motoroff, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_H_OFF_ALL); + lv_big_button_create(scr, "F:/bmp_function1.bin", set_menu.motoroffXY, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_H_OFF_XY); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_H_RETURN); +} + +void lv_clear_home() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_home.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.h new file mode 100644 index 0000000..a8f11d9 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_home.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_home(void); +extern void lv_clear_home(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.cpp new file mode 100644 index 0000000..71a0657 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.cpp @@ -0,0 +1,104 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfig.h" + +#if HAS_TFT_LVGL_UI && USE_SENSORLESS + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/planner.h" +#include "../../../../module/probe.h" +#include "../../../../module/stepper/indirection.h" +#include "../../../../feature/tmc_util.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_SENSITIVITY_RETURN = 1, + ID_SENSITIVITY_X, + ID_SENSITIVITY_Y, + ID_SENSITIVITY_Z, + ID_SENSITIVITY_Z2 +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_SENSITIVITY_RETURN: + lv_clear_homing_sensitivity_settings(); + lv_draw_return_ui(); + break; + case ID_SENSITIVITY_X: + value = x_sensitivity; + lv_clear_homing_sensitivity_settings(); + lv_draw_number_key(); + break; + case ID_SENSITIVITY_Y: + value = y_sensitivity; + lv_clear_homing_sensitivity_settings(); + lv_draw_number_key(); + break; + case ID_SENSITIVITY_Z: + value = z_sensitivity; + lv_clear_homing_sensitivity_settings(); + lv_draw_number_key(); + break; + #if Z2_SENSORLESS + case ID_SENSITIVITY_Z2: + value = z2_sensitivity; + lv_clear_homing_sensitivity_settings(); + lv_draw_number_key(); + break; + #endif + } +} + +void lv_draw_homing_sensitivity_settings(void) { + scr = lv_screen_create(HOMING_SENSITIVITY_UI, machine_menu.HomingSensitivityConfTitle); + + sprintf_P(public_buf_l, PSTR("%d"), TERN(X_SENSORLESS, stepperX.homing_threshold(), 0)); + lv_screen_menu_item_1_edit(scr, machine_menu.X_Sensitivity, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_SENSITIVITY_X, 0, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), TERN(Y_SENSORLESS, stepperY.homing_threshold(), 0)); + lv_screen_menu_item_1_edit(scr, machine_menu.Y_Sensitivity, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_SENSITIVITY_Y, 1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), TERN(Z_SENSORLESS, stepperZ.homing_threshold(), 0)); + lv_screen_menu_item_1_edit(scr, machine_menu.Z_Sensitivity, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_SENSITIVITY_Z, 2, public_buf_l); + + #if Z2_SENSORLESS + sprintf_P(public_buf_l, PSTR("%d"), TERN(Z2_SENSORLESS, stepperZ2.homing_threshold(), 0)); + lv_screen_menu_item_1_edit(scr, machine_menu.Z2_Sensitivity, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_SENSITIVITY_Z2, 3, public_buf_l); + #endif + + lv_screen_menu_item_return(scr, event_handler, ID_SENSITIVITY_RETURN); +} + +void lv_clear_homing_sensitivity_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI && USE_SENSORLESS diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.h new file mode 100644 index 0000000..0c55470 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_homing_sensitivity_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_homing_sensitivity_settings(void); +extern void lv_clear_homing_sensitivity_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.cpp new file mode 100644 index 0000000..38db624 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.cpp @@ -0,0 +1,99 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if BOTH(HAS_TFT_LVGL_UI, HAS_CLASSIC_JERK) + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/planner.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_JERK_RETURN = 1, + ID_JERK_X, + ID_JERK_Y, + ID_JERK_Z, + ID_JERK_E +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_JERK_RETURN: + lv_clear_jerk_settings(); + lv_draw_return_ui(); + break; + case ID_JERK_X: + value = XJerk; + lv_clear_jerk_settings(); + lv_draw_number_key(); + break; + case ID_JERK_Y: + value = YJerk; + lv_clear_jerk_settings(); + lv_draw_number_key(); + break; + case ID_JERK_Z: + value = ZJerk; + lv_clear_jerk_settings(); + lv_draw_number_key(); + break; + case ID_JERK_E: + value = EJerk; + lv_clear_jerk_settings(); + lv_draw_number_key(); + break; + } +} + +void lv_draw_jerk_settings(void) { + char str_1[16]; + scr = lv_screen_create(JERK_UI, machine_menu.JerkConfTitle); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.max_jerk[X_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.X_Jerk, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_JERK_X, 0, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.max_jerk[Y_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.Y_Jerk, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_JERK_Y, 1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.max_jerk[Z_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.Z_Jerk, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_JERK_Z, 2, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.max_jerk[E_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.E_Jerk, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_JERK_E, 3, public_buf_l); + + lv_screen_menu_item_return(scr, event_handler, ID_JERK_RETURN); +} + +void lv_clear_jerk_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI && HAS_CLASSIC_JERK diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.h new file mode 100644 index 0000000..0531dae --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_jerk_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_jerk_settings(void); +extern void lv_clear_jerk_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.cpp new file mode 100644 index 0000000..08615dc --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.cpp @@ -0,0 +1,289 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +#define LV_KB_CTRL_BTN_FLAGS (LV_BTNM_CTRL_NO_REPEAT | LV_BTNM_CTRL_CLICK_TRIG) + +#ifdef FRENCH_KEYBOARD +static const char * kb_map_lc[] = {"1#", "a", "z", "e", "r", "t", "y", "u", "i", "o", "p", LV_SYMBOL_BACKSPACE, "\n", + "ABC", "q", "s", "d", "f", "g", "h", "j", "k", "l", "m", LV_SYMBOL_NEW_LINE, "\n", + "_", "-", "w", "x", "c", "v", "b", "n", ",", ";", ":", "!", "\n", + LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""}; + +static const lv_btnm_ctrl_t kb_ctrl_lc_map[] = { + LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, + LV_KB_CTRL_BTN_FLAGS | 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2}; + +static const char * kb_map_uc[] = {"1#", "A", "Z", "E", "R", "T", "Y", "U", "I", "O", "P", LV_SYMBOL_BACKSPACE, "\n", + "abc", "Q", "S", "D", "F", "G", "H", "J", "K", "L", "M", LV_SYMBOL_NEW_LINE, "\n", + "_", "-", "W", "X", "C", "V", "B", "N", "?", ".", "/", "^", "\n", + LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""}; + +static const lv_btnm_ctrl_t kb_ctrl_uc_map[] = { + LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, + LV_KB_CTRL_BTN_FLAGS | 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2}; + +#else +static const char * kb_map_lc[] = {"1#", "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", LV_SYMBOL_BACKSPACE, "\n", + "ABC", "a", "s", "d", "f", "g", "h", "j", "k", "l", LV_SYMBOL_NEW_LINE, "\n", + "_", "-", "z", "x", "c", "v", "b", "n", "m", ".", ",", ":", "\n", + LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""}; + +static const lv_btnm_ctrl_t kb_ctrl_lc_map[] = { + LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, + LV_KB_CTRL_BTN_FLAGS | 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2}; + +static const char * kb_map_uc[] = {"1#", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", LV_SYMBOL_BACKSPACE, "\n", + "abc", "A", "S", "D", "F", "G", "H", "J", "K", "L", LV_SYMBOL_NEW_LINE, "\n", + "_", "-", "Z", "X", "C", "V", "B", "N", "M", ".", ",", "^", "\n", + LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""}; + +static const lv_btnm_ctrl_t kb_ctrl_uc_map[] = { + LV_KB_CTRL_BTN_FLAGS | 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 7, + LV_KB_CTRL_BTN_FLAGS | 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2}; + +#endif + +static const char * kb_map_spec[] = {"0", "1", "2", "3", "4" ,"5", "6", "7", "8", "9", ".", LV_SYMBOL_BACKSPACE, "\n", + "abc", "+", "-", "/", "*", "=", "%", "!", "?", "#", "<", ">", "\n", + "\\", "@", "$", "(", ")", "{", "}", "[", "]", ";", "\"", "'", "\n", + LV_SYMBOL_CLOSE, LV_SYMBOL_LEFT, " ", LV_SYMBOL_RIGHT, LV_SYMBOL_OK, ""}; + +static const lv_btnm_ctrl_t kb_ctrl_spec_map[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2, + LV_KB_CTRL_BTN_FLAGS | 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + LV_KB_CTRL_BTN_FLAGS | 2, 2, 6, 2, LV_KB_CTRL_BTN_FLAGS | 2}; + +static const lv_btnm_ctrl_t kb_ctrl_num_map[] = { + 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2, + 1, 1, 1, LV_KB_CTRL_BTN_FLAGS | 2, + 1, 1, 1, 2, + 1, 1, 1, 1, 1}; + +static void lv_kb_event_cb(lv_obj_t *kb, lv_event_t event) { + if (event != LV_EVENT_VALUE_CHANGED) return; + + lv_kb_ext_t * ext = (lv_kb_ext_t * )lv_obj_get_ext_attr(kb); + const uint16_t btn_id = lv_btnm_get_active_btn(kb); + if (btn_id == LV_BTNM_BTN_NONE) return; + if (lv_btnm_get_btn_ctrl(kb, btn_id, LV_BTNM_CTRL_HIDDEN | LV_BTNM_CTRL_INACTIVE)) return; + if (lv_btnm_get_btn_ctrl(kb, btn_id, LV_BTNM_CTRL_NO_REPEAT) && event == LV_EVENT_LONG_PRESSED_REPEAT) return; + + const char * txt = lv_btnm_get_active_btn_text(kb); + if (!txt) return; + + // Do the corresponding action according to the text of the button + if (strcmp(txt, "abc") == 0) { + lv_btnm_set_map(kb, kb_map_lc); + lv_btnm_set_ctrl_map(kb, kb_ctrl_lc_map); + return; + } + else if (strcmp(txt, "ABC") == 0) { + lv_btnm_set_map(kb, kb_map_uc); + lv_btnm_set_ctrl_map(kb, kb_ctrl_uc_map); + return; + } + else if (strcmp(txt, "1#") == 0) { + lv_btnm_set_map(kb, kb_map_spec); + lv_btnm_set_ctrl_map(kb, kb_ctrl_spec_map); + return; + } + else if (strcmp(txt, LV_SYMBOL_CLOSE) == 0) { + if (kb->event_cb != lv_kb_def_event_cb) { + lv_clear_keyboard(); + lv_draw_return_ui(); + } + else { + lv_kb_set_ta(kb, nullptr); // De-assign the text area to hide it cursor if needed + lv_obj_del(kb); + return; + } + return; + } + else if (strcmp(txt, LV_SYMBOL_OK) == 0) { + if (kb->event_cb != lv_kb_def_event_cb) { + const char * ret_ta_txt = lv_ta_get_text(ext->ta); + switch (keyboard_value) { + #if ENABLED(MKS_WIFI_MODULE) + case wifiName: + memcpy(uiCfg.wifi_name,ret_ta_txt,sizeof(uiCfg.wifi_name)); + lv_clear_keyboard(); + lv_draw_return_ui(); + break; + case wifiPassWord: + memcpy(uiCfg.wifi_key,ret_ta_txt,sizeof(uiCfg.wifi_name)); + lv_clear_keyboard(); + lv_draw_return_ui(); + break; + case wifiConfig: + ZERO(uiCfg.wifi_name); + memcpy((void *)uiCfg.wifi_name, wifi_list.wifiName[wifi_list.nameIndex], 32); + + ZERO(uiCfg.wifi_key); + memcpy((void *)uiCfg.wifi_key, ret_ta_txt, sizeof(uiCfg.wifi_key)); + + gCfgItems.wifi_mode_sel = STA_MODEL; + + package_to_wifi(WIFI_PARA_SET, (uint8_t *)0, 0); + + public_buf_l[0] = 0xA5; + public_buf_l[1] = 0x09; + public_buf_l[2] = 0x01; + public_buf_l[3] = 0x00; + public_buf_l[4] = 0x01; + public_buf_l[5] = 0xFC; + public_buf_l[6] = 0x00; + raw_send_to_wifi((uint8_t*)public_buf_l, 6); + + last_disp_state = KEY_BOARD_UI; + lv_clear_keyboard(); + wifi_tips_type = TIPS_TYPE_JOINING; + lv_draw_wifi_tips(); + break; + #endif // MKS_WIFI_MODULE + case gcodeCommand: + uint8_t buf[100]; + strncpy((char *)buf,ret_ta_txt,sizeof(buf)); + update_gcode_command(AUTO_LEVELING_COMMAND_ADDR,buf); + lv_clear_keyboard(); + lv_draw_return_ui(); + break; + default: break; + } + } + else + lv_kb_set_ta(kb, nullptr); // De-assign the text area to hide it cursor if needed + return; + } + + // Add the characters to the text area if set + if (!ext->ta) return; + + if (strcmp(txt, "Enter") == 0 || strcmp(txt, LV_SYMBOL_NEW_LINE) == 0) + lv_ta_add_char(ext->ta, '\n'); + else if (strcmp(txt, LV_SYMBOL_LEFT) == 0) + lv_ta_cursor_left(ext->ta); + else if (strcmp(txt, LV_SYMBOL_RIGHT) == 0) + lv_ta_cursor_right(ext->ta); + else if (strcmp(txt, LV_SYMBOL_BACKSPACE) == 0) + lv_ta_del_char(ext->ta); + else if (strcmp(txt, "+/-") == 0) { + uint16_t cur = lv_ta_get_cursor_pos(ext->ta); + const char * ta_txt = lv_ta_get_text(ext->ta); + if (ta_txt[0] == '-') { + lv_ta_set_cursor_pos(ext->ta, 1); + lv_ta_del_char(ext->ta); + lv_ta_add_char(ext->ta, '+'); + lv_ta_set_cursor_pos(ext->ta, cur); + } + else if (ta_txt[0] == '+') { + lv_ta_set_cursor_pos(ext->ta, 1); + lv_ta_del_char(ext->ta); + lv_ta_add_char(ext->ta, '-'); + lv_ta_set_cursor_pos(ext->ta, cur); + } + else { + lv_ta_set_cursor_pos(ext->ta, 0); + lv_ta_add_char(ext->ta, '-'); + lv_ta_set_cursor_pos(ext->ta, cur + 1); + } + } + else { + lv_ta_add_text(ext->ta, txt); + } +} + +void lv_draw_keyboard() { + scr = lv_screen_create(KEY_BOARD_UI, ""); + + // Create styles for the keyboard + static lv_style_t rel_style, pr_style; + + lv_style_copy(&rel_style, &lv_style_btn_rel); + rel_style.body.radius = 0; + rel_style.body.border.width = 1; + rel_style.body.main_color = lv_color_make(0xA9, 0x62, 0x1D); + rel_style.body.grad_color = lv_color_make(0xA7, 0x59, 0x0E); + + lv_style_copy(&pr_style, &lv_style_btn_pr); + pr_style.body.radius = 0; + pr_style.body.border.width = 1; + pr_style.body.main_color = lv_color_make(0x72, 0x42, 0x15); + pr_style.body.grad_color = lv_color_make(0x6A, 0x3A, 0x0C); + + // Create a keyboard and apply the styles + lv_obj_t *kb = lv_kb_create(scr, nullptr); + lv_btnm_set_map(kb, kb_map_lc); + lv_btnm_set_ctrl_map(kb, kb_ctrl_lc_map); + lv_obj_set_base_dir(kb, LV_BIDI_DIR_LTR); + + lv_obj_set_event_cb(kb, lv_kb_event_cb); + lv_kb_set_cursor_manage(kb, true); + lv_kb_set_style(kb, LV_KB_STYLE_BG, &lv_style_transp_tight); + lv_kb_set_style(kb, LV_KB_STYLE_BTN_REL, &rel_style); + lv_kb_set_style(kb, LV_KB_STYLE_BTN_PR, &pr_style); + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + } + #endif + + // Create a text area. The keyboard will write here + lv_obj_t *ta = lv_ta_create(scr, nullptr); + lv_obj_align(ta, nullptr, LV_ALIGN_IN_TOP_MID, 0, 10); + if (keyboard_value == gcodeCommand) { + get_gcode_command(AUTO_LEVELING_COMMAND_ADDR,(uint8_t *)public_buf_m); + public_buf_m[sizeof(public_buf_m)-1] = 0; + lv_ta_set_text(ta, public_buf_m); + } + else { + lv_ta_set_text(ta, ""); + } + + // Assign the text area to the keyboard + lv_kb_set_ta(kb, ta); +} + +void lv_clear_keyboard() { + lv_obj_del(scr); +} + + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.h new file mode 100644 index 0000000..0013dc4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_keyboard.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_keyboard(); +extern void lv_clear_keyboard(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_language.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_language.cpp new file mode 100644 index 0000000..7edb73b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_language.cpp @@ -0,0 +1,208 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" +#include <string.h> + +enum { + ID_CN = 1, + ID_T_CN, + ID_EN, + ID_RU, + ID_ES, + ID_FR, + ID_IT, + ID_L_RETURN +}; + +#define SELECTED 1 +#define UNSELECTED 0 + +static void disp_language(uint8_t language, uint8_t state); + +extern lv_group_t *g; +static lv_obj_t *scr; +static lv_obj_t *buttonCN, *buttonT_CN, *buttonEN, *buttonRU; +static lv_obj_t *buttonES, *buttonFR, *buttonIT; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_CN: + disp_language(gCfgItems.language, UNSELECTED); + lv_imgbtn_set_src_both(buttonCN, "F:/bmp_simplified_cn_sel.bin"); + lv_obj_refresh_ext_draw_pad(buttonCN); + gCfgItems.language = LANG_SIMPLE_CHINESE; + update_spi_flash(); + disp_language_init(); + break; + case ID_T_CN: + disp_language(gCfgItems.language, UNSELECTED); + lv_imgbtn_set_src_both(buttonT_CN, "F:/bmp_traditional_cn_sel.bin"); + lv_obj_refresh_ext_draw_pad(buttonT_CN); + gCfgItems.language = LANG_COMPLEX_CHINESE; + update_spi_flash(); + disp_language_init(); + break; + case ID_EN: + disp_language(gCfgItems.language, UNSELECTED); + lv_imgbtn_set_src_both(buttonEN, "F:/bmp_english_sel.bin"); + lv_obj_refresh_ext_draw_pad(buttonEN); + gCfgItems.language = LANG_ENGLISH; + update_spi_flash(); + disp_language_init(); + break; + case ID_RU: + disp_language(gCfgItems.language, UNSELECTED); + lv_imgbtn_set_src_both(buttonRU, "F:/bmp_russian_sel.bin"); + lv_obj_refresh_ext_draw_pad(buttonRU); + gCfgItems.language = LANG_RUSSIAN; + update_spi_flash(); + disp_language_init(); + break; + case ID_ES: + disp_language(gCfgItems.language, UNSELECTED); + lv_imgbtn_set_src_both(buttonES, "F:/bmp_spanish_sel.bin"); + lv_obj_refresh_ext_draw_pad(buttonES); + gCfgItems.language = LANG_SPANISH; + update_spi_flash(); + disp_language_init(); + break; + case ID_FR: + disp_language(gCfgItems.language, UNSELECTED); + lv_imgbtn_set_src_both(buttonFR, "F:/bmp_french_sel.bin"); + lv_obj_refresh_ext_draw_pad(buttonFR); + gCfgItems.language = LANG_FRENCH; + update_spi_flash(); + disp_language_init(); + break; + case ID_IT: + disp_language(gCfgItems.language, UNSELECTED); + lv_imgbtn_set_src_both(buttonIT, "F:/bmp_italy_sel.bin"); + lv_obj_refresh_ext_draw_pad(buttonIT); + gCfgItems.language = LANG_ITALY; + update_spi_flash(); + disp_language_init(); + break; + case ID_L_RETURN: + buttonCN = nullptr; + buttonT_CN = nullptr; + buttonEN = nullptr; + buttonRU = nullptr; + buttonES = nullptr; + buttonFR = nullptr; + buttonFR = nullptr; + buttonIT = nullptr; + lv_clear_language(); + lv_draw_set(); + break; + } +} + +static void disp_language(uint8_t language, uint8_t state) { + uint16_t id; + lv_obj_t *obj; + + public_buf_l[0] = '\0'; + + switch (language) { + case LANG_SIMPLE_CHINESE: + id = ID_CN; + strcpy_P(public_buf_l, PSTR("F:/bmp_simplified_cn")); + obj = buttonCN; + break; + case LANG_COMPLEX_CHINESE: + id = ID_T_CN; + strcpy_P(public_buf_l, PSTR("F:/bmp_traditional_cn")); + obj = buttonT_CN; + break; + case LANG_ENGLISH: + id = ID_EN; + strcpy_P(public_buf_l, PSTR("F:/bmp_english")); + obj = buttonEN; + break; + case LANG_RUSSIAN: + id = ID_RU; + strcpy_P(public_buf_l, PSTR("F:/bmp_russian")); + obj = buttonRU; + break; + case LANG_SPANISH: + id = ID_ES; + strcpy_P(public_buf_l, PSTR("F:/bmp_spanish")); + obj = buttonES; + break; + case LANG_FRENCH: + id = ID_FR; + strcpy_P(public_buf_l, PSTR("F:/bmp_french")); + obj = buttonFR; + break; + case LANG_ITALY: + id = ID_IT; + strcpy_P(public_buf_l, PSTR("F:/bmp_italy")); + obj = buttonIT; + break; + default: + id = ID_CN; + strcpy_P(public_buf_l, PSTR("F:/bmp_simplified_cn")); + obj = buttonCN; + break; + } + + if (state == SELECTED) strcat_P(public_buf_l, PSTR("_sel")); + + strcat_P(public_buf_l, PSTR(".bin")); + + lv_obj_set_event_cb_mks(obj, event_handler, id, "", 0); + lv_imgbtn_set_src_both(obj, public_buf_l); + + if (state == UNSELECTED) lv_obj_refresh_ext_draw_pad(obj); +} + +void lv_draw_language(void) { + scr = lv_screen_create(LANGUAGE_UI); + // Create image buttons + buttonCN = lv_big_button_create(scr, "F:/bmp_simplified_cn.bin", language_menu.chinese_s, INTERVAL_V, titleHeight, event_handler, ID_CN); + lv_obj_clear_protect(buttonCN, LV_PROTECT_FOLLOW); + buttonT_CN = lv_big_button_create(scr, "F:/bmp_traditional_cn.bin", language_menu.chinese_t, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_T_CN); + buttonEN = lv_big_button_create(scr, "F:/bmp_english.bin", language_menu.english, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_EN); + buttonRU = lv_big_button_create(scr, "F:/bmp_russian.bin", language_menu.russian, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_RU); + buttonES = lv_big_button_create(scr, "F:/bmp_spanish.bin", language_menu.spanish, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_ES); + buttonFR = lv_big_button_create(scr, "F:/bmp_french.bin", language_menu.french, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_FR); + buttonIT = lv_big_button_create(scr, "F:/bmp_italy.bin", language_menu.italy, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_IT); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_L_RETURN); + disp_language(gCfgItems.language, SELECTED); +} + +void lv_clear_language() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_language.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_language.h new file mode 100644 index 0000000..d4ee14f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_language.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_language(void); +extern void lv_clear_language(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.cpp new file mode 100644 index 0000000..c1f3c57 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.cpp @@ -0,0 +1,104 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_LEVEL_RETURN = 1, + ID_LEVEL_POSITION, + ID_LEVEL_COMMAND, + ID_LEVEL_ZOFFSET, + ID_LEVEL_BLTOUCH, + ID_LEVEL_TOUCHMI +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_LEVEL_RETURN: + lv_clear_level_settings(); + lv_draw_return_ui(); + break; + case ID_LEVEL_POSITION: + lv_clear_level_settings(); + lv_draw_manual_level_pos_settings(); + break; + case ID_LEVEL_COMMAND: + keyboard_value = gcodeCommand; + lv_clear_level_settings(); + lv_draw_keyboard(); + break; + #if HAS_BED_PROBE + case ID_LEVEL_ZOFFSET: + lv_clear_level_settings(); + lv_draw_auto_level_offset_settings(); + break; + #endif + #if ENABLED(BLTOUCH) + case ID_LEVEL_BLTOUCH: + lv_clear_level_settings(); + bltouch_do_init(); + lv_draw_bltouch_settings(); + break; + #endif + #if ENABLED(TOUCH_MI_PROBE) + case ID_LEVEL_TOUCHMI: + lv_clear_level_settings(); + lv_draw_touchmi_settings(); + break; + #endif + } +} + +void lv_draw_level_settings(void) { + + scr = lv_screen_create(LEVELING_PARA_UI, machine_menu.LevelingParaConfTitle); + lv_screen_menu_item(scr, machine_menu.LevelingManuPosConf, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_LEVEL_POSITION, 0); + lv_screen_menu_item(scr, machine_menu.LevelingAutoCommandConf, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_LEVEL_COMMAND, 1); + #if HAS_BED_PROBE + lv_screen_menu_item(scr, machine_menu.LevelingAutoZoffsetConf, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_LEVEL_ZOFFSET, 2); + #endif + #if ENABLED(BLTOUCH) + lv_screen_menu_item(scr, machine_menu.BLTouchLevelingConf, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_LEVEL_BLTOUCH, 3); + #endif + #if ENABLED(TOUCH_MI_PROBE) + lv_screen_menu_item(scr, machine_menu.LevelingTouchmiConf, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_LEVEL_TOUCHMI, 3); + #endif + lv_screen_menu_item_return(scr, event_handler, ID_LEVEL_RETURN); +} + +void lv_clear_level_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.h new file mode 100644 index 0000000..cdca9c8 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_level_settings.h @@ -0,0 +1,35 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_level_settings(void); +extern void lv_draw_bltouch_settings(void); +extern void lv_draw_touchmi_settings(void); +extern void lv_clear_level_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.cpp new file mode 100644 index 0000000..ed98dca --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.cpp @@ -0,0 +1,84 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_PARA_RETURN = 1, + ID_PARA_MACHINE, + ID_PARA_MOTOR, + ID_PARA_LEVEL, + ID_PARA_ADVANCE +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_PARA_RETURN: + lv_clear_machine_para(); + lv_draw_return_ui(); + break; + case ID_PARA_MACHINE: + lv_clear_machine_para(); + lv_draw_machine_settings(); + break; + case ID_PARA_MOTOR: + lv_clear_machine_para(); + lv_draw_motor_settings(); + break; + case ID_PARA_LEVEL: + lv_clear_machine_para(); + lv_draw_level_settings(); + break; + case ID_PARA_ADVANCE: + lv_clear_machine_para(); + lv_draw_advance_settings(); + break; + } +} + +void lv_draw_machine_para(void) { + scr = lv_screen_create(MACHINE_PARA_UI); + lv_screen_menu_item(scr, MachinePara_menu.MachineSetting, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_PARA_MACHINE, 0); + lv_screen_menu_item(scr, MachinePara_menu.MotorSetting, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_PARA_MOTOR, 1); + lv_screen_menu_item(scr, MachinePara_menu.leveling, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_PARA_LEVEL, 2); + lv_screen_menu_item(scr, MachinePara_menu.AdvanceSetting, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_PARA_ADVANCE, 3); + lv_screen_menu_item_return(scr, event_handler, ID_PARA_RETURN); +} + +void lv_clear_machine_para() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.h new file mode 100644 index 0000000..e830f75 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_para.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_machine_para(void); +extern void lv_clear_machine_para(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.cpp new file mode 100644 index 0000000..7b7cc1e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.cpp @@ -0,0 +1,82 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_MACHINE_RETURN = 1, + ID_MACHINE_ACCELERATION, + ID_MACHINE_FEEDRATE, + ID_MACHINE_JERK +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_MACHINE_RETURN: + lv_clear_machine_settings(); + lv_draw_return_ui(); + break; + case ID_MACHINE_ACCELERATION: + lv_clear_machine_settings(); + lv_draw_acceleration_settings(); + break; + case ID_MACHINE_FEEDRATE: + lv_clear_machine_settings(); + lv_draw_max_feedrate_settings(); + break; + #if HAS_CLASSIC_JERK + case ID_MACHINE_JERK: + lv_clear_machine_settings(); + lv_draw_jerk_settings(); + break; + #endif + } +} + +void lv_draw_machine_settings(void) { + scr = lv_screen_create(MACHINE_SETTINGS_UI, machine_menu.MachineConfigTitle); + lv_screen_menu_item(scr, machine_menu.AccelerationConf, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_MACHINE_ACCELERATION, 0); + lv_screen_menu_item(scr, machine_menu.MaxFeedRateConf, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_MACHINE_FEEDRATE, 1); + #if HAS_CLASSIC_JERK + lv_screen_menu_item(scr, machine_menu.JerkConf, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_MACHINE_JERK, 2); + #endif + lv_screen_menu_item_return(scr, event_handler, ID_MACHINE_RETURN); +} + +void lv_clear_machine_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.h new file mode 100644 index 0000000..38d02e7 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_machine_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_machine_settings(void); +extern void lv_clear_machine_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp new file mode 100644 index 0000000..338cb1f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.cpp @@ -0,0 +1,135 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../gcode/queue.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_M_POINT1 = 1, + ID_M_POINT2, + ID_M_POINT3, + ID_M_POINT4, + ID_M_POINT5, + ID_MANUAL_RETURN +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + + switch (obj->mks_obj_id) { + case ID_M_POINT1: + if (queue.length == 0) { + if (uiCfg.leveling_first_time) { + queue.enqueue_now_P(PSTR("G28")); + uiCfg.leveling_first_time = 0; + } + queue.enqueue_now_P(PSTR("G1 Z10")); + sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[0][0], (int)gCfgItems.levelingPos[0][1]); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G1 Z0")); + } + break; + case ID_M_POINT2: + if (queue.length == 0) { + if (uiCfg.leveling_first_time) { + queue.enqueue_now_P(PSTR("G28")); + uiCfg.leveling_first_time = 0; + } + queue.enqueue_now_P(PSTR("G1 Z10")); + sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[1][0], (int)gCfgItems.levelingPos[1][1]); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G1 Z0")); + } + break; + case ID_M_POINT3: + if (queue.length == 0) { + if (uiCfg.leveling_first_time) { + queue.enqueue_now_P(PSTR("G28")); + uiCfg.leveling_first_time = 0; + } + queue.enqueue_now_P(PSTR("G1 Z10")); + sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[2][0], (int)gCfgItems.levelingPos[2][1]); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G1 Z0")); + } + + break; + case ID_M_POINT4: + if (queue.length == 0) { + if (uiCfg.leveling_first_time) { + queue.enqueue_now_P(PSTR("G28")); + uiCfg.leveling_first_time = 0; + } + queue.enqueue_now_P(PSTR("G1 Z10")); + sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[3][0], (int)gCfgItems.levelingPos[3][1]); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G1 Z0")); + } + break; + case ID_M_POINT5: + if (queue.length == 0) { + if (uiCfg.leveling_first_time) { + queue.enqueue_now_P(PSTR("G28")); + uiCfg.leveling_first_time = 0; + } + queue.enqueue_now_P(PSTR("G1 Z10")); + sprintf_P(public_buf_l, PSTR("G1 X%d Y%d"), (int)gCfgItems.levelingPos[4][0], (int)gCfgItems.levelingPos[4][1]); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G1 Z0")); + } + break; + case ID_MANUAL_RETURN: + lv_clear_manualLevel(); + lv_draw_tool(); + break; + } +} + +void lv_draw_manualLevel(void) { + scr = lv_screen_create(LEVELING_UI); + // Create an Image button + lv_obj_t *buttonPoint1 = lv_big_button_create(scr, "F:/bmp_leveling1.bin", leveling_menu.position1, INTERVAL_V, titleHeight, event_handler, ID_M_POINT1); + lv_obj_clear_protect(buttonPoint1, LV_PROTECT_FOLLOW); + lv_big_button_create(scr, "F:/bmp_leveling2.bin", leveling_menu.position2, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_M_POINT2); + lv_big_button_create(scr, "F:/bmp_leveling3.bin", leveling_menu.position3, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_M_POINT3); + lv_big_button_create(scr, "F:/bmp_leveling4.bin", leveling_menu.position4, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_M_POINT4); + lv_big_button_create(scr, "F:/bmp_leveling5.bin", leveling_menu.position5, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_POINT5); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_MANUAL_RETURN); +} + +void lv_clear_manualLevel() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.h new file mode 100644 index 0000000..60de0b4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_manuaLevel.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_manualLevel(void); +extern void lv_clear_manualLevel(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.cpp new file mode 100644 index 0000000..60defc7 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.cpp @@ -0,0 +1,146 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/planner.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_MANUAL_POS_RETURN = 1, + ID_MANUAL_POS_X1, + ID_MANUAL_POS_Y1, + ID_MANUAL_POS_X2, + ID_MANUAL_POS_Y2, + ID_MANUAL_POS_X3, + ID_MANUAL_POS_Y3, + ID_MANUAL_POS_X4, + ID_MANUAL_POS_Y4, + ID_MANUAL_POS_X5, + ID_MANUAL_POS_Y5, + ID_MANUAL_POS_DOWN, + ID_MANUAL_POS_UP +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_MANUAL_POS_RETURN: + uiCfg.para_ui_page = 0; + lv_clear_manual_level_pos_settings(); + lv_draw_return_ui(); + return; + case ID_MANUAL_POS_X1: + value = level_pos_x1; + break; + case ID_MANUAL_POS_Y1: + value = level_pos_y1; + break; + case ID_MANUAL_POS_X2: + value = level_pos_x2; + break; + case ID_MANUAL_POS_Y2: + value = level_pos_y2; + break; + case ID_MANUAL_POS_X3: + value = level_pos_x3; + break; + case ID_MANUAL_POS_Y3: + value = level_pos_y3; + break; + case ID_MANUAL_POS_X4: + value = level_pos_x4; + break; + case ID_MANUAL_POS_Y4: + value = level_pos_y4; + break; + case ID_MANUAL_POS_X5: + value = level_pos_x5; + break; + case ID_MANUAL_POS_Y5: + value = level_pos_y5; + break; + case ID_MANUAL_POS_UP: + uiCfg.para_ui_page = 0; + lv_clear_manual_level_pos_settings(); + lv_draw_manual_level_pos_settings(); + return; + case ID_MANUAL_POS_DOWN: + uiCfg.para_ui_page = 1; + lv_clear_manual_level_pos_settings(); + lv_draw_manual_level_pos_settings(); + return; + } + lv_clear_manual_level_pos_settings(); + lv_draw_number_key(); +} + +void lv_draw_manual_level_pos_settings(void) { + char buf2[50]; + + scr = lv_screen_create(MANUAL_LEVELING_POSIGION_UI, machine_menu.LevelingParaConfTitle); + + if (uiCfg.para_ui_page != 1) { + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[0][0]); + sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[0][1]); + lv_screen_menu_item_2_edit(scr, leveling_menu.position1, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_MANUAL_POS_Y1, 0, buf2, ID_MANUAL_POS_X1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[1][0]); + sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[1][1]); + lv_screen_menu_item_2_edit(scr, leveling_menu.position2, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_MANUAL_POS_Y2, 1, buf2, ID_MANUAL_POS_X2, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[2][0]); + sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[2][1]); + lv_screen_menu_item_2_edit(scr, leveling_menu.position3, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_MANUAL_POS_Y3, 2, buf2, ID_MANUAL_POS_X3, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[3][0]); + sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[3][1]); + lv_screen_menu_item_2_edit(scr, leveling_menu.position4, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_MANUAL_POS_Y4, 3, buf2, ID_MANUAL_POS_X4, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_MANUAL_POS_DOWN); + } + else { + sprintf_P(public_buf_l, PSTR("%d"), gCfgItems.levelingPos[4][0]); + sprintf_P(buf2, PSTR("%d"), gCfgItems.levelingPos[4][1]); + lv_screen_menu_item_2_edit(scr, leveling_menu.position5, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_MANUAL_POS_Y5, 0, buf2, ID_MANUAL_POS_X5, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_MANUAL_POS_UP); + } + + lv_screen_menu_item_return(scr, event_handler, ID_MANUAL_POS_RETURN); +} + +void lv_clear_manual_level_pos_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.h new file mode 100644 index 0000000..8e89ecf --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_manual_level_pos_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_manual_level_pos_settings(void); +extern void lv_clear_manual_level_pos_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.cpp new file mode 100644 index 0000000..0877cf9 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.cpp @@ -0,0 +1,119 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/planner.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_FEED_RETURN = 1, + ID_FEED_X, + ID_FEED_Y, + ID_FEED_Z, + ID_FEED_E0, + ID_FEED_E1, + ID_FEED_DOWN, + ID_FEED_UP +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + + lv_clear_max_feedrate_settings(); + switch (obj->mks_obj_id) { + case ID_FEED_RETURN: + uiCfg.para_ui_page = 0; + lv_draw_return_ui(); + return; + case ID_FEED_X: + value = XMaxFeedRate; + break; + case ID_FEED_Y: + value = YMaxFeedRate; + break; + case ID_FEED_Z: + value = ZMaxFeedRate; + break; + case ID_FEED_E0: + value = E0MaxFeedRate; + break; + case ID_FEED_E1: + value = E1MaxFeedRate; + break; + case ID_FEED_UP: + uiCfg.para_ui_page = 0; + lv_draw_max_feedrate_settings(); + return; + case ID_FEED_DOWN: + uiCfg.para_ui_page = 1; + lv_draw_max_feedrate_settings(); + return; + } + lv_draw_number_key(); + +} + +void lv_draw_max_feedrate_settings(void) { + char str_1[16]; + scr = lv_screen_create(MAXFEEDRATE_UI, machine_menu.MaxFeedRateConfTitle); + + if (uiCfg.para_ui_page != 1) { + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[X_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.XMaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_FEED_X, 0, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[Y_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.YMaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_FEED_Y, 1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[Z_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.ZMaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_FEED_Z, 2, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[E_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.E0MaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_FEED_E0, 3, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_FEED_DOWN); + } + else { + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[E_AXIS_N(1)], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.E1MaxFeedRate, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_FEED_E1, 0, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_FEED_UP); + } + + lv_screen_menu_item_return(scr, event_handler, ID_FEED_RETURN); +} + +void lv_clear_max_feedrate_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.h new file mode 100644 index 0000000..78caca5 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_max_feedrate_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_max_feedrate_settings(void); +extern void lv_clear_max_feedrate_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_more.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_more.cpp new file mode 100644 index 0000000..dbc218b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_more.cpp @@ -0,0 +1,119 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "../../../../MarlinCore.h" +#include "../../../../gcode/queue.h" + +#include "lv_conf.h" +#include "draw_ui.h" + +extern lv_group_t * g; +static lv_obj_t * scr; + +enum { + ID_CUSTOM_1 = 1, + ID_CUSTOM_2, + ID_CUSTOM_3, + ID_CUSTOM_4, + ID_CUSTOM_5, + ID_CUSTOM_6, + ID_CUSTOM_7, + ID_M_RETURN +}; + +static void event_handler(lv_obj_t * obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + #if ENABLED(USER_CMD_1_ENABLE) + case ID_CUSTOM_1: queue.inject_P(PSTR(USER_GCODE_1)); break; + #endif + #if ENABLED(USER_CMD_2_ENABLE) + case ID_CUSTOM_2: queue.inject_P(PSTR(USER_GCODE_2)); break; + #endif + #if ENABLED(USER_CMD_3_ENABLE) + case ID_CUSTOM_3: queue.inject_P(PSTR(USER_GCODE_3)); break; + #endif + #if ENABLED(USER_CMD_4_ENABLE) + case ID_CUSTOM_4: queue.inject_P(PSTR(USER_GCODE_4)); break; + #endif + #if ENABLED(USER_CMD_5_ENABLE) + case ID_CUSTOM_5: queue.inject_P(PSTR(USER_GCODE_5)); break; + #endif + #if ENABLED(USER_CMD_6_ENABLE) + case ID_CUSTOM_6: queue.inject_P(PSTR(USER_GCODE_6)); break; + #endif + #if ENABLED(USER_CMD_7_ENABLE) + case ID_CUSTOM_7: queue.inject_P(PSTR(USER_GCODE_7)); break; + #endif + case ID_M_RETURN: + lv_clear_more(); + lv_draw_tool(); + break; + } +} + +void lv_draw_more(void) { + scr = lv_screen_create(MORE_UI); + + #if ENABLED(USER_CMD_1_ENABLE) + lv_big_button_create(scr, "F:/bmp_custom1.bin", more_menu.custom1, INTERVAL_V, titleHeight, event_handler, ID_CUSTOM_1); + #endif + + #if ENABLED(USER_CMD_2_ENABLE) + lv_big_button_create(scr, "F:/bmp_custom2.bin", more_menu.custom2, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_CUSTOM_2); + #endif + + #if ENABLED(USER_CMD_3_ENABLE) + lv_big_button_create(scr, "F:/bmp_custom3.bin", more_menu.custom3, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_CUSTOM_3); + #endif + + #if ENABLED(USER_CMD_4_ENABLE) + lv_big_button_create(scr, "F:/bmp_custom4.bin", more_menu.custom4, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_CUSTOM_4); + #endif + + #if ENABLED(USER_CMD_5_ENABLE) + lv_big_button_create(scr, "F:/bmp_custom5.bin", more_menu.custom5, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_5); + #endif + + #if ENABLED(USER_CMD_6_ENABLE) + lv_big_button_create(scr, "F:/bmp_custom6.bin", more_menu.custom6, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_6); + #endif + + #if ENABLED(USER_CMD_7_ENABLE) + lv_big_button_create(scr, "F:/bmp_custom7.bin", more_menu.custom7, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_CUSTOM_7); + #endif + + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN); + +} + +void lv_clear_more() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_more.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_more.h new file mode 100644 index 0000000..9dfa705 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_more.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus +extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_more(void); +extern void lv_clear_more(); + +#ifdef __cplusplus +} /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.cpp new file mode 100644 index 0000000..219ea5a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.cpp @@ -0,0 +1,98 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_MOTOR_RETURN = 1, + ID_MOTOR_STEPS, + ID_MOTOR_TMC_CURRENT, + ID_MOTOR_STEP_MODE, + ID_HOME_SENSE +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + lv_clear_motor_settings(); + switch (obj->mks_obj_id) { + case ID_MOTOR_RETURN: + lv_draw_return_ui(); + break; + case ID_MOTOR_STEPS: + lv_draw_step_settings(); + break; + #if USE_SENSORLESS + case ID_HOME_SENSE: + lv_draw_homing_sensitivity_settings(); + break; + #endif + + #if HAS_TRINAMIC_CONFIG + case ID_MOTOR_TMC_CURRENT: + lv_draw_tmc_current_settings(); + break; + #if HAS_STEALTHCHOP + case ID_MOTOR_STEP_MODE: + lv_draw_tmc_step_mode_settings(); + break; + #endif + #endif + } +} + +void lv_draw_motor_settings(void) { + int index = 0; + + scr = lv_screen_create(MOTOR_SETTINGS_UI, machine_menu.MotorConfTitle); + lv_screen_menu_item(scr, machine_menu.StepsConf, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_MOTOR_STEPS, index++); + #if USE_SENSORLESS + lv_screen_menu_item(scr, machine_menu.HomingSensitivityConf, PARA_UI_POS_X, PARA_UI_POS_Y * (index + 1), event_handler, ID_HOME_SENSE, index); + index++; + #endif + #if HAS_TRINAMIC_CONFIG + lv_screen_menu_item(scr, machine_menu.TMCcurrentConf, PARA_UI_POS_X, PARA_UI_POS_Y * (index + 1), event_handler, ID_MOTOR_TMC_CURRENT, index); + index++; + #if HAS_STEALTHCHOP + lv_screen_menu_item(scr, machine_menu.TMCStepModeConf, PARA_UI_POS_X, PARA_UI_POS_Y * (index + 1), event_handler, ID_MOTOR_STEP_MODE, index); + index++; + #endif + #endif + lv_screen_menu_item_return(scr, event_handler, ID_MOTOR_RETURN); +} + +void lv_clear_motor_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.h new file mode 100644 index 0000000..9a1c7a4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_motor_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_motor_settings(void); +extern void lv_clear_motor_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp new file mode 100644 index 0000000..2b76829 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.cpp @@ -0,0 +1,211 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../gcode/queue.h" +#include "../../../../module/motion.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +static lv_obj_t *labelV, *buttonV, *labelP; +static lv_task_t *updatePosTask; +static char cur_label = 'Z'; +static float cur_pos = 0; + +void disp_cur_pos(); + +enum { + ID_M_X_P = 1, + ID_M_X_N, + ID_M_Y_P, + ID_M_Y_N, + ID_M_Z_P, + ID_M_Z_N, + ID_M_STEP, + ID_M_RETURN +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + char str_1[16]; + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_M_X_P: + if (queue.length <= (BUFSIZE - 3)) { + queue.enqueue_one_P(PSTR("G91")); + sprintf_P(public_buf_l, PSTR("G1 X%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_one_P(PSTR("G90")); + cur_label = 'X'; + } + break; + case ID_M_X_N: + if (queue.length <= (BUFSIZE - 3)) { + queue.enqueue_now_P(PSTR("G91")); + sprintf_P(public_buf_l, PSTR("G1 X-%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G90")); + cur_label = 'X'; + } + break; + case ID_M_Y_P: + if (queue.length <= (BUFSIZE - 3)) { + queue.enqueue_now_P(PSTR("G91")); + sprintf_P(public_buf_l, PSTR("G1 Y%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G90")); + cur_label = 'Y'; + } + break; + case ID_M_Y_N: + if (queue.length <= (BUFSIZE - 3)) { + queue.enqueue_now_P(PSTR("G91")); + sprintf_P(public_buf_l, PSTR("G1 Y-%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G90")); + cur_label = 'Y'; + } + break; + case ID_M_Z_P: + if (queue.length <= (BUFSIZE - 3)) { + queue.enqueue_now_P(PSTR("G91")); + sprintf_P(public_buf_l, PSTR("G1 Z%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G90")); + cur_label = 'Z'; + } + break; + case ID_M_Z_N: + if (queue.length <= (BUFSIZE - 3)) { + queue.enqueue_now_P(PSTR("G91")); + sprintf_P(public_buf_l, PSTR("G1 Z-%s F%d"), dtostrf(uiCfg.move_dist, 1, 3, str_1), uiCfg.moveSpeed); + queue.enqueue_one_now(public_buf_l); + queue.enqueue_now_P(PSTR("G90")); + cur_label = 'Z'; + } + break; + case ID_M_STEP: + if (abs(10 * (int)uiCfg.move_dist) == 100) + uiCfg.move_dist = 0.1; + else + uiCfg.move_dist *= (float)10; + disp_move_dist(); + break; + case ID_M_RETURN: + lv_clear_cur_ui(); + lv_draw_return_ui(); + return; + } + disp_cur_pos(); +} + +void refresh_pos(lv_task_t *) +{ + switch(cur_label) { + case 'X': cur_pos = current_position.x; break; + case 'Y': cur_pos = current_position.y; break; + case 'Z': cur_pos = current_position.z; break; + default: return; + } + disp_cur_pos(); +} +void lv_draw_move_motor(void) { + scr = lv_screen_create(MOVE_MOTOR_UI); + lv_obj_t *buttonXI = lv_big_button_create(scr, "F:/bmp_xAdd.bin", move_menu.x_add, INTERVAL_V, titleHeight, event_handler, ID_M_X_P); + lv_obj_clear_protect(buttonXI, LV_PROTECT_FOLLOW); + lv_big_button_create(scr, "F:/bmp_xDec.bin", move_menu.x_dec, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_X_N); + lv_big_button_create(scr, "F:/bmp_yAdd.bin", move_menu.y_add, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_M_Y_P); + lv_big_button_create(scr, "F:/bmp_yDec.bin", move_menu.y_dec, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_Y_N); + lv_big_button_create(scr, "F:/bmp_zAdd.bin", move_menu.z_add, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_M_Z_P); + lv_big_button_create(scr, "F:/bmp_zDec.bin", move_menu.z_dec, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_Z_N); + + // button with image and label changed dynamically by disp_move_dist + buttonV = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_M_STEP); + labelV = lv_label_create_empty(buttonV); + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonV); + } + #endif + + + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_M_RETURN); + + // We need to patch the title to leave some space on the right for displaying the status + lv_obj_t * title = lv_obj_get_child_back(scr, NULL); + if (title != NULL) lv_obj_set_width(title, TFT_WIDTH - 101); + labelP = lv_label_create(scr, TFT_WIDTH - 100, TITLE_YPOS, "Z:0.0mm"); + if (labelP != NULL) { + updatePosTask = lv_task_create(refresh_pos, 300, LV_TASK_PRIO_LOWEST, 0); + } + + + disp_move_dist(); + disp_cur_pos(); +} + + +void disp_cur_pos() { + char str_1[16]; + sprintf_P(public_buf_l, PSTR("%c:%s mm"), cur_label, dtostrf(cur_pos, 1, 1, str_1)); + if (labelP) lv_label_set_text(labelP, public_buf_l); +} + +void disp_move_dist() { + if ((int)(10 * uiCfg.move_dist) == 1) + lv_imgbtn_set_src_both(buttonV, "F:/bmp_step_move0_1.bin"); + else if ((int)(10 * uiCfg.move_dist) == 10) + lv_imgbtn_set_src_both(buttonV, "F:/bmp_step_move1.bin"); + else if ((int)(10 * uiCfg.move_dist) == 100) + lv_imgbtn_set_src_both(buttonV, "F:/bmp_step_move10.bin"); + + if (gCfgItems.multiple_language) { + if ((int)(10 * uiCfg.move_dist) == 1) { + lv_label_set_text(labelV, move_menu.step_01mm); + lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if ((int)(10 * uiCfg.move_dist) == 10) { + lv_label_set_text(labelV, move_menu.step_1mm); + lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if ((int)(10 * uiCfg.move_dist) == 100) { + lv_label_set_text(labelV, move_menu.step_10mm); + lv_obj_align(labelV, buttonV, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void lv_clear_move_motor() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_task_del(updatePosTask); + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.h new file mode 100644 index 0000000..4e41c5f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_move_motor.h @@ -0,0 +1,34 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_move_motor(void); +extern void lv_clear_move_motor(); +extern void disp_move_dist(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.cpp new file mode 100644 index 0000000..9cacf2f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.cpp @@ -0,0 +1,772 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../gcode/gcode.h" +#include "../../../../gcode/queue.h" +#include "../../../../module/planner.h" +#include "../../../../module/temperature.h" +#include "../../../../inc/MarlinConfig.h" + +#if ENABLED(POWER_LOSS_RECOVERY) + #include "../../../../feature/powerloss.h" +#endif + +#if HAS_TRINAMIC_CONFIG + #include "../../../../module/stepper/indirection.h" + #include "../../../../feature/tmc_util.h" +#endif + +#if HAS_BED_PROBE + #include "../../../../module/probe.h" +#endif + +extern lv_group_t *g; +static lv_obj_t *scr; +static lv_obj_t *buttonValue = nullptr; +static lv_obj_t *labelValue = nullptr; + +static char key_value[11] = { 0 }; +static uint8_t cnt = 0; +static bool point_flag = true; + +enum { + ID_NUM_KEY1 = 1, + ID_NUM_KEY2, + ID_NUM_KEY3, + ID_NUM_KEY4, + ID_NUM_KEY5, + ID_NUM_KEY6, + ID_NUM_KEY7, + ID_NUM_KEY8, + ID_NUM_KEY9, + ID_NUM_KEY0, + ID_NUM_BACK, + ID_NUM_RESET, + ID_NUM_CONFIRM, + ID_NUM_POINT, + ID_NUM_NEGATIVE +}; + +static void disp_key_value() { + char *temp; + char str_1[16]; + #if HAS_TRINAMIC_CONFIG + float milliamps; + #endif + + switch (value) { + case PrintAcceleration: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.acceleration, 1, 1, str_1)); + break; + case RetractAcceleration: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.retract_acceleration, 1, 1, str_1)); + break; + case TravelAcceleration: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.travel_acceleration, 1, 1, str_1)); + break; + case XAcceleration: + sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[X_AXIS]); + break; + case YAcceleration: + sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[Y_AXIS]); + break; + case ZAcceleration: + sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[Z_AXIS]); + break; + case E0Acceleration: + sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[E_AXIS]); + break; + case E1Acceleration: + sprintf_P(public_buf_m, PSTR("%d"), (int)planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)]); + break; + case XMaxFeedRate: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[X_AXIS], 1, 1, str_1)); + break; + case YMaxFeedRate: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[Y_AXIS], 1, 1, str_1)); + break; + case ZMaxFeedRate: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[Z_AXIS], 1, 1, str_1)); + break; + case E0MaxFeedRate: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[E_AXIS], 1, 1, str_1)); + break; + case E1MaxFeedRate: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.max_feedrate_mm_s[E_AXIS_N(1)], 1, 1, str_1)); + break; + + case XJerk: + #if HAS_CLASSIC_JERK + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.max_jerk[X_AXIS], 1, 1, str_1)); + #endif + break; + case YJerk: + #if HAS_CLASSIC_JERK + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.max_jerk[Y_AXIS], 1, 1, str_1)); + #endif + break; + case ZJerk: + #if HAS_CLASSIC_JERK + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.max_jerk[Z_AXIS], 1, 1, str_1)); + #endif + break; + case EJerk: + #if HAS_CLASSIC_JERK + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.max_jerk[E_AXIS], 1, 1, str_1)); + #endif + break; + + case Xstep: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[X_AXIS], 1, 1, str_1)); + break; + case Ystep: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[Y_AXIS], 1, 1, str_1)); + + break; + case Zstep: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[Z_AXIS], 1, 1, str_1)); + + break; + case E0step: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[E_AXIS], 1, 1, str_1)); + + break; + case E1step: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[E_AXIS_N(1)], 1, 1, str_1)); + break; + + case Xcurrent: + #if AXIS_IS_TMC(X) + milliamps = stepperX.getMilliamps(); + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + #endif + break; + + case Ycurrent: + #if AXIS_IS_TMC(Y) + milliamps = stepperY.getMilliamps(); + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + #endif + break; + + case Zcurrent: + #if AXIS_IS_TMC(Z) + milliamps = stepperZ.getMilliamps(); + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + #endif + break; + + case E0current: + #if AXIS_IS_TMC(E0) + milliamps = stepperE0.getMilliamps(); + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + #endif + break; + + case E1current: + #if AXIS_IS_TMC(E1) + milliamps = stepperE1.getMilliamps(); + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + #endif + break; + + case pause_pos_x: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(gCfgItems.pausePosX, 1, 1, str_1)); + break; + case pause_pos_y: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(gCfgItems.pausePosY, 1, 1, str_1)); + break; + case pause_pos_z: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(gCfgItems.pausePosZ, 1, 1, str_1)); + break; + case level_pos_x1: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[0][0]); + break; + case level_pos_y1: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[0][1]); + break; + case level_pos_x2: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[1][0]); + break; + case level_pos_y2: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[1][1]); + break; + case level_pos_x3: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[2][0]); + break; + case level_pos_y3: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[2][1]); + break; + case level_pos_x4: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[3][0]); + break; + case level_pos_y4: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[3][1]); + break; + case level_pos_x5: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[4][0]); + break; + case level_pos_y5: + sprintf_P(public_buf_m, PSTR("%d"), (int)gCfgItems.levelingPos[4][1]); + break; + #if HAS_BED_PROBE + case x_offset: + #if HAS_PROBE_XY_OFFSET + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(probe.offset.x, 1, 3, str_1)); + #endif + break; + case y_offset: + #if HAS_PROBE_XY_OFFSET + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(probe.offset.y, 1, 3, str_1)); + #endif + break; + case z_offset: + sprintf_P(public_buf_m, PSTR("%s"), dtostrf(probe.offset.z, 1, 3, str_1)); + break; + #endif + case load_length: + sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filamentchange_load_length); + break; + case load_speed: + sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filamentchange_load_speed); + break; + case unload_length: + sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filamentchange_unload_length); + break; + case unload_speed: + sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filamentchange_unload_speed); + break; + case filament_temp: + sprintf_P(public_buf_m, PSTR("%d"), gCfgItems.filament_limit_temper); + break; + case x_sensitivity: + #if X_SENSORLESS + sprintf_P(public_buf_m, PSTR("%d"), TERN(X_SENSORLESS, stepperX.homing_threshold(), 0)); + #endif + break; + case y_sensitivity: + #if Y_SENSORLESS + sprintf_P(public_buf_m, PSTR("%d"), TERN(Y_SENSORLESS, stepperY.homing_threshold(), 0)); + #endif + break; + case z_sensitivity: + #if Z_SENSORLESS + sprintf_P(public_buf_m, PSTR("%d"), TERN(Z_SENSORLESS, stepperZ.homing_threshold(), 0)); + #endif + break; + case z2_sensitivity: + #if Z2_SENSORLESS + sprintf_P(public_buf_m, PSTR("%d"), TERN(Z2_SENSORLESS, stepperZ2.homing_threshold(), 0)); + #endif + break; + } + + strcpy(key_value, public_buf_m); + cnt = strlen(key_value); + temp = strchr(key_value, '.'); + point_flag = !temp; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + +} + +static void set_value_confirm() { + #if HAS_TRINAMIC_CONFIG + uint16_t current_mA; + #endif + switch (value) { + case PrintAcceleration: + planner.settings.acceleration = atof(key_value); + break; + case RetractAcceleration: + planner.settings.retract_acceleration = atof(key_value); + break; + case TravelAcceleration: + planner.settings.travel_acceleration = atof(key_value); + break; + case XAcceleration: + planner.settings.max_acceleration_mm_per_s2[X_AXIS] = atof(key_value); + break; + case YAcceleration: + planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = atof(key_value); + break; + case ZAcceleration: + planner.settings.max_acceleration_mm_per_s2[Z_AXIS] = atof(key_value); + break; + case E0Acceleration: + planner.settings.max_acceleration_mm_per_s2[E_AXIS] = atof(key_value); + break; + case E1Acceleration: + planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(1)] = atof(key_value); + break; + case XMaxFeedRate: + planner.settings.max_feedrate_mm_s[X_AXIS] = atof(key_value); + break; + case YMaxFeedRate: + planner.settings.max_feedrate_mm_s[Y_AXIS] = atof(key_value); + break; + case ZMaxFeedRate: + planner.settings.max_feedrate_mm_s[Z_AXIS] = atof(key_value); + break; + case E0MaxFeedRate: + planner.settings.max_feedrate_mm_s[E_AXIS] = atof(key_value); + break; + case E1MaxFeedRate: + planner.settings.max_feedrate_mm_s[E_AXIS_N(1)] = atof(key_value); + break; + case XJerk: + #if HAS_CLASSIC_JERK + planner.max_jerk[X_AXIS] = atof(key_value); + #endif + break; + case YJerk: + #if HAS_CLASSIC_JERK + planner.max_jerk[Y_AXIS] = atof(key_value); + #endif + break; + case ZJerk: + #if HAS_CLASSIC_JERK + planner.max_jerk[Z_AXIS] = atof(key_value); + #endif + break; + case EJerk: + #if HAS_CLASSIC_JERK + planner.max_jerk[E_AXIS] = atof(key_value); + #endif + break; + case Xstep: + planner.settings.axis_steps_per_mm[X_AXIS] = atof(key_value); + planner.refresh_positioning(); + break; + case Ystep: + planner.settings.axis_steps_per_mm[Y_AXIS] = atof(key_value); + planner.refresh_positioning(); + break; + case Zstep: + planner.settings.axis_steps_per_mm[Z_AXIS] = atof(key_value); + planner.refresh_positioning(); + break; + case E0step: + planner.settings.axis_steps_per_mm[E_AXIS] = atof(key_value); + planner.refresh_positioning(); + break; + case E1step: + planner.settings.axis_steps_per_mm[E_AXIS_N(1)] = atof(key_value); + planner.refresh_positioning(); + break; + case Xcurrent: + #if AXIS_IS_TMC(X) + current_mA = atoi(key_value); + stepperX.rms_current(current_mA); + #endif + break; + case Ycurrent: + #if AXIS_IS_TMC(Y) + current_mA = atoi(key_value); + stepperY.rms_current(current_mA); + #endif + break; + case Zcurrent: + #if AXIS_IS_TMC(Z) + current_mA = atoi(key_value); + stepperZ.rms_current(current_mA); + #endif + break; + case E0current: + #if AXIS_IS_TMC(E0) + current_mA = atoi(key_value); + stepperE0.rms_current(current_mA); + #endif + break; + case E1current: + #if AXIS_IS_TMC(E1) + current_mA = atoi(key_value); + stepperE1.rms_current(current_mA); + #endif + break; + case pause_pos_x: + gCfgItems.pausePosX = atof(key_value); + update_spi_flash(); + break; + case pause_pos_y: + gCfgItems.pausePosY = atof(key_value); + update_spi_flash(); + break; + case pause_pos_z: + gCfgItems.pausePosZ = atof(key_value); + update_spi_flash(); + break; + case level_pos_x1: + gCfgItems.levelingPos[0][0] = atoi(key_value); + update_spi_flash(); + break; + case level_pos_y1: + gCfgItems.levelingPos[0][1] = atoi(key_value); + update_spi_flash(); + break; + case level_pos_x2: + gCfgItems.levelingPos[1][0] = atoi(key_value); + update_spi_flash(); + break; + case level_pos_y2: + gCfgItems.levelingPos[1][1] = atoi(key_value); + update_spi_flash(); + break; + case level_pos_x3: + gCfgItems.levelingPos[2][0] = atoi(key_value); + update_spi_flash(); + break; + case level_pos_y3: + gCfgItems.levelingPos[2][1] = atoi(key_value); + update_spi_flash(); + break; + case level_pos_x4: + gCfgItems.levelingPos[3][0] = atoi(key_value); + update_spi_flash(); + break; + case level_pos_y4: + gCfgItems.levelingPos[3][1] = atoi(key_value); + update_spi_flash(); + break; + case level_pos_x5: + gCfgItems.levelingPos[4][0] = atoi(key_value); + update_spi_flash(); + break; + case level_pos_y5: + gCfgItems.levelingPos[4][1] = atoi(key_value); + update_spi_flash(); + break; + #if HAS_BED_PROBE + case x_offset: + #if HAS_PROBE_XY_OFFSET + float x; + x = atof(key_value); + if (WITHIN(x, -(X_BED_SIZE), X_BED_SIZE)) + probe.offset.x = x; + #endif + break; + case y_offset: + #if HAS_PROBE_XY_OFFSET + float y; + y = atof(key_value); + if (WITHIN(y, -(Y_BED_SIZE), Y_BED_SIZE)) + probe.offset.y = y; + #endif + break; + case z_offset: + float z; + z = atof(key_value); + if (WITHIN(z, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX)) + probe.offset.z = z; + break; + #endif + case load_length: + gCfgItems.filamentchange_load_length = atoi(key_value); + uiCfg.filament_loading_time = (uint32_t)((gCfgItems.filamentchange_load_length*60.0/gCfgItems.filamentchange_load_speed)+0.5); + update_spi_flash(); + break; + case load_speed: + gCfgItems.filamentchange_load_speed = atoi(key_value); + uiCfg.filament_loading_time = (uint32_t)((gCfgItems.filamentchange_load_length*60.0/gCfgItems.filamentchange_load_speed)+0.5); + update_spi_flash(); + break; + case unload_length: + gCfgItems.filamentchange_unload_length = atoi(key_value); + uiCfg.filament_unloading_time = (uint32_t)((gCfgItems.filamentchange_unload_length*60.0/gCfgItems.filamentchange_unload_speed)+0.5); + update_spi_flash(); + break; + case unload_speed: + gCfgItems.filamentchange_unload_speed = atoi(key_value); + uiCfg.filament_unloading_time = (uint32_t)((gCfgItems.filamentchange_unload_length*60.0/gCfgItems.filamentchange_unload_speed)+0.5); + update_spi_flash(); + break; + case filament_temp: + gCfgItems.filament_limit_temper = atoi(key_value); + update_spi_flash(); + break; + case x_sensitivity: + #if X_SENSORLESS + stepperX.homing_threshold(atoi(key_value)); + #endif + break; + case y_sensitivity: + #if Y_SENSORLESS + stepperY.homing_threshold(atoi(key_value)); + #endif + break; + case z_sensitivity: + #if Z_SENSORLESS + stepperZ.homing_threshold(atoi(key_value)); + #endif + break; + case z2_sensitivity: + #if Z2_SENSORLESS + stepperZ2.homing_threshold(atoi(key_value)); + #endif + break; + } + watchdog_refresh(); + gcode.process_subcommands_now_P(PSTR("M500")); +} + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_NUM_KEY1: + if (cnt <= 10) { + key_value[cnt] = (char)'1'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_KEY2: + if (cnt <= 10) { + key_value[cnt] = (char)'2'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_KEY3: + if (cnt <= 10) { + key_value[cnt] = (char)'3'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_KEY4: + if (cnt <= 10) { + key_value[cnt] = (char)'4'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_KEY5: + if (cnt <= 10) { + key_value[cnt] = (char)'5'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_KEY6: + if (cnt <= 10) { + key_value[cnt] = (char)'6'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_KEY7: + if (cnt <= 10) { + key_value[cnt] = (char)'7'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_KEY8: + if (cnt <= 10) { + key_value[cnt] = (char)'8'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_KEY9: + if (cnt <= 10) { + key_value[cnt] = (char)'9'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_KEY0: + if (cnt <= 10) { + key_value[cnt] = (char)'0'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_BACK: + if (cnt > 0) cnt--; + if (key_value[cnt] == (char)'.') point_flag = true; + key_value[cnt] = (char)'\0'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + break; + case ID_NUM_RESET: + ZERO(key_value); + cnt = 0; + key_value[cnt] = (char)'0'; + point_flag = true; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + break; + case ID_NUM_POINT: + if (cnt != 0 && point_flag) { + point_flag = false; + key_value[cnt] = (char)'.'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_NEGATIVE: + if (cnt == 0) { + key_value[cnt] = (char)'-'; + lv_label_set_text(labelValue, key_value); + lv_obj_align(labelValue, buttonValue, LV_ALIGN_CENTER, 0, 0); + cnt++; + } + break; + case ID_NUM_CONFIRM: + last_disp_state = NUMBER_KEY_UI; + if (strlen(key_value) != 0) set_value_confirm(); + lv_clear_number_key(); + lv_draw_return_ui(); + break; + } +} + +void lv_draw_number_key(void) { + scr = lv_screen_create(NUMBER_KEY_UI, ""); + + buttonValue = lv_btn_create(scr, 92, 40, 296, 40, event_handler, 0, &style_num_text); + labelValue = lv_label_create_empty(buttonValue); + + lv_obj_t *NumberKey_1 = lv_btn_create(scr, 92, 90, 68, 40, event_handler, ID_NUM_KEY1, &style_num_key_pre); + lv_obj_t *labelKey_1 = lv_label_create_empty(NumberKey_1); + lv_label_set_text(labelKey_1, machine_menu.key_1); + lv_obj_align(labelKey_1, NumberKey_1, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *NumberKey_2 = lv_btn_create(scr, 168, 90, 68, 40, event_handler, ID_NUM_KEY2, &style_num_key_pre); + lv_obj_t *labelKey_2 = lv_label_create_empty(NumberKey_2); + lv_label_set_text(labelKey_2, machine_menu.key_2); + lv_obj_align(labelKey_2, NumberKey_2, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *NumberKey_3 = lv_btn_create(scr, 244, 90, 68, 40, event_handler, ID_NUM_KEY3, &style_num_key_pre); + lv_obj_t *labelKey_3 = lv_label_create_empty(NumberKey_3); + lv_label_set_text(labelKey_3, machine_menu.key_3); + lv_obj_align(labelKey_3, NumberKey_3, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *NumberKey_4 = lv_btn_create(scr, 92, 140, 68, 40, event_handler, ID_NUM_KEY4, &style_num_key_pre); + lv_obj_t *labelKey_4 = lv_label_create_empty(NumberKey_4); + lv_label_set_text(labelKey_4, machine_menu.key_4); + lv_obj_align(labelKey_4, NumberKey_4, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *NumberKey_5 = lv_btn_create(scr, 168, 140, 68, 40, event_handler, ID_NUM_KEY5, &style_num_key_pre); + lv_obj_t *labelKey_5 = lv_label_create_empty(NumberKey_5); + lv_label_set_text(labelKey_5, machine_menu.key_5); + lv_obj_align(labelKey_5, NumberKey_5, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *NumberKey_6 = lv_btn_create(scr, 244, 140, 68, 40, event_handler, ID_NUM_KEY6, &style_num_key_pre); + lv_obj_t *labelKey_6 = lv_label_create_empty(NumberKey_6); + lv_label_set_text(labelKey_6, machine_menu.key_6); + lv_obj_align(labelKey_6, NumberKey_6, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *NumberKey_7 = lv_btn_create(scr, 92, 190, 68, 40, event_handler, ID_NUM_KEY7, &style_num_key_pre); + lv_obj_t *labelKey_7 = lv_label_create_empty(NumberKey_7); + lv_label_set_text(labelKey_7, machine_menu.key_7); + lv_obj_align(labelKey_7, NumberKey_7, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *NumberKey_8 = lv_btn_create(scr, 168, 190, 68, 40, event_handler, ID_NUM_KEY8, &style_num_key_pre); + lv_obj_t *labelKey_8 = lv_label_create_empty(NumberKey_8); + lv_label_set_text(labelKey_8, machine_menu.key_8); + lv_obj_align(labelKey_8, NumberKey_8, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *NumberKey_9 = lv_btn_create(scr, 244, 190, 68, 40, event_handler, ID_NUM_KEY9, &style_num_key_pre); + lv_obj_t *labelKey_9 = lv_label_create_empty(NumberKey_9); + lv_label_set_text(labelKey_9, machine_menu.key_9); + lv_obj_align(labelKey_9, NumberKey_9, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *NumberKey_0 = lv_btn_create(scr, 92, 240, 68, 40, event_handler, ID_NUM_KEY0, &style_num_key_pre); + lv_obj_t *labelKey_0 = lv_label_create_empty(NumberKey_0); + lv_label_set_text(labelKey_0, machine_menu.key_0); + lv_obj_align(labelKey_0, NumberKey_0, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *Minus = lv_btn_create(scr, 168, 240, 68, 40, event_handler, ID_NUM_NEGATIVE, &style_num_key_pre); + lv_obj_t *labelMinus = lv_label_create_empty(Minus); + lv_label_set_text(labelMinus, machine_menu.negative); + lv_obj_align(labelMinus, Minus, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *KeyPoint = lv_btn_create(scr, 244, 240, 68, 40, event_handler, ID_NUM_POINT, &style_num_key_pre); + lv_obj_t *labelKeyPoint = lv_label_create_empty(KeyPoint); + lv_label_set_text(labelKeyPoint, machine_menu.key_point); + lv_obj_align(labelKeyPoint, KeyPoint, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *KeyBack = lv_btn_create(scr, 320, 90, 68, 40, event_handler, ID_NUM_BACK, &style_num_key_pre); + lv_obj_t *labelKeyBack = lv_label_create_empty(KeyBack); + lv_label_set_text(labelKeyBack, machine_menu.key_back); + lv_obj_align(labelKeyBack, KeyBack, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *KeyReset = lv_btn_create(scr, 320, 140, 68, 40, event_handler, ID_NUM_RESET, &style_num_key_pre); + lv_obj_t *labelKeyReset = lv_label_create_empty(KeyReset); + lv_label_set_text(labelKeyReset, machine_menu.key_reset); + lv_obj_align(labelKeyReset, KeyReset, LV_ALIGN_CENTER, 0, 0); + + lv_obj_t *KeyConfirm = lv_btn_create(scr, 320, 190, 68, 90, event_handler, ID_NUM_CONFIRM, &style_num_key_pre); + lv_obj_t *labelKeyConfirm = lv_label_create_empty(KeyConfirm); + lv_label_set_text(labelKeyConfirm, machine_menu.key_confirm); + lv_obj_align(labelKeyConfirm, KeyConfirm, LV_ALIGN_CENTER, 0, 0); + + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, NumberKey_1); + lv_group_add_obj(g, NumberKey_2); + lv_group_add_obj(g, NumberKey_3); + lv_group_add_obj(g, KeyBack); + lv_group_add_obj(g, NumberKey_4); + lv_group_add_obj(g, NumberKey_5); + lv_group_add_obj(g, NumberKey_6); + lv_group_add_obj(g, KeyReset); + lv_group_add_obj(g, NumberKey_7); + lv_group_add_obj(g, NumberKey_8); + lv_group_add_obj(g, NumberKey_9); + lv_group_add_obj(g, NumberKey_0); + lv_group_add_obj(g, Minus); + lv_group_add_obj(g, KeyPoint); + lv_group_add_obj(g, KeyConfirm); + } + #endif + + disp_key_value(); +} + +void lv_clear_number_key() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.h new file mode 100644 index 0000000..7902da3 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_number_key.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_number_key(void); +extern void lv_clear_number_key(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.cpp new file mode 100644 index 0000000..9233991 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.cpp @@ -0,0 +1,230 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/temperature.h" +#include "../../../../module/motion.h" +#include "../../../../sd/cardreader.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_O_PRE_HEAT = 1, + ID_O_EXTRUCT, + ID_O_MOV, + ID_O_FILAMENT, + ID_O_SPEED, + ID_O_RETURN, + ID_O_FAN, + ID_O_POWER_OFF, + ID_O_BABY_STEP +}; + +static lv_obj_t *label_PowerOff; +static lv_obj_t *buttonPowerOff; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_O_PRE_HEAT: + lv_clear_operation(); + lv_draw_preHeat(); + break; + case ID_O_EXTRUCT: + uiCfg.moveSpeed_bak = (uint16_t)feedrate_mm_s; + lv_clear_operation(); + lv_draw_extrusion(); + break; + case ID_O_MOV: + lv_clear_operation(); + lv_draw_move_motor(); + break; + case ID_O_FILAMENT: + #if HAS_MULTI_EXTRUDER + uiCfg.curSprayerChoose_bak = active_extruder; + #endif + if (uiCfg.print_state == WORKING) { + #if ENABLED(SDSUPPORT) + card.pauseSDPrint(); + stop_print_time(); + uiCfg.print_state = PAUSING; + #endif + } + uiCfg.moveSpeed_bak = (uint16_t)feedrate_mm_s; + uiCfg.desireSprayerTempBak = thermalManager.temp_hotend[active_extruder].target; + lv_clear_operation(); + lv_draw_filament_change(); + break; + case ID_O_FAN: + lv_clear_operation(); + lv_draw_fan(); + break; + case ID_O_SPEED: + lv_clear_operation(); + lv_draw_change_speed(); + break; + case ID_O_RETURN: + lv_clear_cur_ui(); + lv_draw_return_ui(); + break; + case ID_O_POWER_OFF: + if (gCfgItems.finish_power_off) { + gCfgItems.finish_power_off = false; + lv_imgbtn_set_src_both(buttonPowerOff, "F:/bmp_manual_off.bin"); + lv_label_set_text(label_PowerOff, printing_more_menu.manual); + } + else { + gCfgItems.finish_power_off = true; + lv_imgbtn_set_src_both(buttonPowerOff, "F:/bmp_auto_off.bin"); + lv_label_set_text(label_PowerOff, printing_more_menu.auto_close); + } + lv_obj_align(label_PowerOff, buttonPowerOff, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + lv_obj_refresh_ext_draw_pad(label_PowerOff); + update_spi_flash(); + break; + case ID_O_BABY_STEP: + lv_clear_operation(); + lv_draw_baby_stepping(); + break; + } +} + +void lv_draw_operation(void) { + lv_obj_t *buttonExtrusion = nullptr, *buttonSpeed = nullptr, + *buttonBack = nullptr, + *labelPreHeat = nullptr, *labelExtrusion = nullptr, + *label_Back = nullptr, *label_Speed = nullptr, *label_Fan = nullptr, + *buttonMove = nullptr, *label_Move = nullptr, + *buttonBabyStep = nullptr, *label_BabyStep = nullptr, + *label_Filament = nullptr; + + scr = lv_screen_create(OPERATE_UI); + + // Create image buttons + lv_obj_t *buttonPreHeat = lv_imgbtn_create(scr, "F:/bmp_temp.bin", INTERVAL_V, titleHeight, event_handler, ID_O_PRE_HEAT); + lv_obj_t *buttonFilament = lv_imgbtn_create(scr, "F:/bmp_filamentchange.bin", BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_O_FILAMENT); + lv_obj_t *buttonFan = lv_imgbtn_create(scr, "F:/bmp_fan.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_O_FAN); + buttonPowerOff = lv_imgbtn_create(scr, gCfgItems.finish_power_off ? "F:/bmp_auto_off.bin" : "F:/bmp_manual_off.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_O_POWER_OFF); + + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonPreHeat); + lv_group_add_obj(g, buttonFilament); + lv_group_add_obj(g, buttonFan); + lv_group_add_obj(g, buttonPowerOff); + } + #endif + + if (uiCfg.print_state != WORKING) { + buttonExtrusion = lv_imgbtn_create(scr, "F:/bmp_extrude_opr.bin", INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_EXTRUCT); + buttonMove = lv_imgbtn_create(scr, "F:/bmp_move_opr.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_MOV); + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonExtrusion); + lv_group_add_obj(g, buttonMove); + } + #endif + } + else { + buttonSpeed = lv_imgbtn_create(scr, "F:/bmp_speed.bin", INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_SPEED); + buttonBabyStep = lv_imgbtn_create(scr, "F:/bmp_mov.bin", BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_BABY_STEP); + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonSpeed); + lv_group_add_obj(g, buttonBabyStep); + } + #endif + } + + buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_O_RETURN); + + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_add_obj(g, buttonBack); + #endif + + // Create labels on the image buttons + labelPreHeat = lv_label_create_empty(buttonPreHeat); + label_Filament = lv_label_create_empty(buttonFilament); + label_Fan = lv_label_create_empty(buttonFan); + label_PowerOff = lv_label_create_empty(buttonPowerOff); + + if (uiCfg.print_state != WORKING) { + labelExtrusion = lv_label_create_empty(buttonExtrusion); + label_Move = lv_label_create_empty(buttonMove); + } + else { + label_Speed = lv_label_create_empty(buttonSpeed); + label_BabyStep = lv_label_create_empty(buttonBabyStep); + } + label_Back = lv_label_create_empty(buttonBack); + + if (gCfgItems.multiple_language) { + lv_label_set_text(labelPreHeat, operation_menu.temp); + lv_obj_align(labelPreHeat, buttonPreHeat, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + + lv_label_set_text(label_Filament, operation_menu.filament); + lv_obj_align(label_Filament, buttonFilament, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + + lv_label_set_text(label_Fan, operation_menu.fan); + lv_obj_align(label_Fan, buttonFan, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + + if (gCfgItems.finish_power_off) + lv_label_set_text(label_PowerOff, printing_more_menu.auto_close); + else + lv_label_set_text(label_PowerOff, printing_more_menu.manual); + lv_obj_align(label_PowerOff, buttonPowerOff, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + + if (uiCfg.print_state != WORKING) { + lv_label_set_text(labelExtrusion, operation_menu.extr); + lv_obj_align(labelExtrusion, buttonExtrusion, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + + lv_label_set_text(label_Move, operation_menu.move); + lv_obj_align(label_Move, buttonMove, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else { + lv_label_set_text(label_Speed, operation_menu.speed); + lv_obj_align(label_Speed, buttonSpeed, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + + lv_label_set_text(label_BabyStep, operation_menu.babystep); + lv_obj_align(label_BabyStep, buttonBabyStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + + lv_label_set_text(label_Back, common_menu.text_back); + lv_obj_align(label_Back, buttonBack, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } +} + +void lv_clear_operation() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.h new file mode 100644 index 0000000..0257812 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_operation.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_operation(void); +extern void lv_clear_operation(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.cpp new file mode 100644 index 0000000..fb7434e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.cpp @@ -0,0 +1,51 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if BOTH(HAS_TFT_LVGL_UI, ADVANCED_PAUSE_FEATURE) + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../feature/pause.h" +#include "../../../../inc/MarlinConfig.h" + +void lv_draw_pause_message(const PauseMessage msg) { + switch (msg) { + case PAUSE_MESSAGE_PAUSING: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_PAUSING); break; + case PAUSE_MESSAGE_CHANGING: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_CHANGING); break; + case PAUSE_MESSAGE_UNLOAD: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_UNLOAD); break; + case PAUSE_MESSAGE_WAITING: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_WAITING); break; + case PAUSE_MESSAGE_INSERT: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_INSERT); break; + case PAUSE_MESSAGE_LOAD: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_LOAD); break; + case PAUSE_MESSAGE_PURGE: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_PURGE); break; + case PAUSE_MESSAGE_RESUME: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_RESUME); break; + case PAUSE_MESSAGE_HEAT: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_HEAT); break; + case PAUSE_MESSAGE_HEATING: lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_HEATING); break; + case PAUSE_MESSAGE_OPTION: pause_menu_response = PAUSE_RESPONSE_WAIT_FOR; + lv_clear_cur_ui(); lv_draw_dialog(DIALOG_PAUSE_MESSAGE_OPTION); break; + case PAUSE_MESSAGE_STATUS: + default: break; + } +} + +#endif // HAS_TFT_LVGL_UI && ADVANCED_PAUSE_FEATURE diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.h new file mode 100644 index 0000000..88222f0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_message.h @@ -0,0 +1,32 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_pause_message(const PauseMessage msg); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.cpp new file mode 100644 index 0000000..be7c81f --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.cpp @@ -0,0 +1,85 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/planner.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_PAUSE_RETURN = 1, + ID_PAUSE_X, + ID_PAUSE_Y, + ID_PAUSE_Z +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + lv_clear_pause_position(); + switch (obj->mks_obj_id) { + case ID_PAUSE_RETURN: + lv_draw_return_ui(); + return; + case ID_PAUSE_X: + value = pause_pos_x; + break; + case ID_PAUSE_Y: + value = pause_pos_y; + break; + case ID_PAUSE_Z: + value = pause_pos_z; + break; + } + lv_draw_number_key(); +} + +void lv_draw_pause_position(void) { + char str_1[16]; + scr = lv_screen_create(PAUSE_POS_UI, machine_menu.PausePosText); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(gCfgItems.pausePosX, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.xPos, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_PAUSE_X, 0, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(gCfgItems.pausePosY, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.yPos, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_PAUSE_Y, 1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(gCfgItems.pausePosZ, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.zPos, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_PAUSE_Z, 2, public_buf_l); + + lv_screen_menu_item_return(scr, event_handler, ID_PAUSE_RETURN); +} + +void lv_clear_pause_position() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.h new file mode 100644 index 0000000..3e9e079 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_pause_position.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_pause_position(void); +extern void lv_clear_pause_position(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.cpp new file mode 100644 index 0000000..b38dbf9 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.cpp @@ -0,0 +1,297 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/temperature.h" +#include "../../../../inc/MarlinConfig.h" +#include "../../../../module/motion.h" + +static lv_obj_t *scr; +extern lv_group_t* g; +static lv_obj_t *buttonType, *buttonStep; +static lv_obj_t *labelType; +static lv_obj_t *labelStep; +static lv_obj_t *tempText1; + +enum { + ID_P_ADD = 1, + ID_P_DEC, + ID_P_TYPE, + ID_P_STEP, + ID_P_OFF, + ID_P_RETURN +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_P_ADD: + if (uiCfg.curTempType == 0) { + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target += uiCfg.stepHeat; + if (uiCfg.curSprayerChoose == 0) { + if ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target > (HEATER_0_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1))) { + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = (float)HEATER_0_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1); + } + } + #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER + else if ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target > (HEATER_1_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1))) { + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = (float)HEATER_1_MAXTEMP - (WATCH_TEMP_INCREASE + TEMP_HYSTERESIS + 1); + } + #endif + thermalManager.start_watching_hotend(uiCfg.curSprayerChoose); + } + #if HAS_HEATED_BED + else { + thermalManager.temp_bed.target += uiCfg.stepHeat; + if ((int)thermalManager.temp_bed.target > BED_MAXTEMP - (WATCH_BED_TEMP_INCREASE + TEMP_BED_HYSTERESIS + 1)) { + thermalManager.temp_bed.target = (float)BED_MAXTEMP - (WATCH_BED_TEMP_INCREASE + TEMP_BED_HYSTERESIS + 1); + } + thermalManager.start_watching_bed(); + } + #endif + disp_desire_temp(); + break; + case ID_P_DEC: + if (uiCfg.curTempType == 0) { + if ((int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target > uiCfg.stepHeat) + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target -= uiCfg.stepHeat; + else + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = 0; + + thermalManager.start_watching_hotend(uiCfg.curSprayerChoose); + } + #if HAS_HEATED_BED + else { + if ((int)thermalManager.temp_bed.target > uiCfg.stepHeat) + thermalManager.temp_bed.target -= uiCfg.stepHeat; + else + thermalManager.temp_bed.target = 0; + + thermalManager.start_watching_bed(); + } + #endif + disp_desire_temp(); + break; + case ID_P_TYPE: + if (uiCfg.curTempType == 0) { + if (ENABLED(HAS_MULTI_EXTRUDER)) { + #if DISABLED(SINGLENOZZLE) + if (uiCfg.curSprayerChoose == 0) { + uiCfg.curSprayerChoose = 1; + } + else if (uiCfg.curSprayerChoose == 1) { + if (TEMP_SENSOR_BED != 0) { + uiCfg.curTempType = 1; + } + else { + uiCfg.curTempType = 0; + uiCfg.curSprayerChoose = 0; + } + } + #else + if (TEMP_SENSOR_BED != 0) { + uiCfg.curTempType = 1; + } + else { + uiCfg.curTempType = 0; + } + #endif + } + else if (uiCfg.curSprayerChoose == 0) { + if (TEMP_SENSOR_BED != 0) + uiCfg.curTempType = 1; + else + uiCfg.curTempType = 0; + } + } + else if (uiCfg.curTempType == 1) { + uiCfg.curSprayerChoose = 0; + uiCfg.curTempType = 0; + } + disp_temp_type(); + break; + case ID_P_STEP: + switch (uiCfg.stepHeat) { + case 1: uiCfg.stepHeat = 5; break; + case 5: uiCfg.stepHeat = 10; break; + case 10: uiCfg.stepHeat = 1; break; + default: break; + } + disp_step_heat(); + break; + case ID_P_OFF: + if (uiCfg.curTempType == 0) { + thermalManager.temp_hotend[uiCfg.curSprayerChoose].target = 0; + thermalManager.start_watching_hotend(uiCfg.curSprayerChoose); + } + #if HAS_HEATED_BED + else { + thermalManager.temp_bed.target = 0; + thermalManager.start_watching_bed(); + } + #endif + disp_desire_temp(); + break; + case ID_P_RETURN: + lv_clear_cur_ui(); + lv_draw_return_ui(); + break; + } +} + +void lv_draw_preHeat(void) { + scr = lv_screen_create(PRE_HEAT_UI); + + // Create image buttons + lv_big_button_create(scr, "F:/bmp_Add.bin", preheat_menu.add, INTERVAL_V, titleHeight, event_handler, ID_P_ADD); + lv_big_button_create(scr, "F:/bmp_Dec.bin", preheat_menu.dec, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_P_DEC); + + buttonType = lv_imgbtn_create(scr, nullptr, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_TYPE); + buttonStep = lv_imgbtn_create(scr, nullptr, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_STEP); + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonType); + lv_group_add_obj(g, buttonStep); + } + #endif + + lv_big_button_create(scr, "F:/bmp_speed0.bin", preheat_menu.off, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_OFF); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_P_RETURN); + + // Create labels on the image buttons + labelType = lv_label_create_empty(buttonType); + labelStep = lv_label_create_empty(buttonStep); + + #if ENABLED(SINGLENOZZLE) + uiCfg.curSprayerChoose = 0; + #else + uiCfg.curSprayerChoose = active_extruder; + #endif + + disp_temp_type(); + disp_step_heat(); + + tempText1 = lv_label_create_empty(scr); + lv_obj_set_style(tempText1, &tft_style_label_rel); + disp_desire_temp(); +} + +void disp_temp_type() { + if (uiCfg.curTempType == 0) { + #if DISABLED(SINGLENOZZLE) + if (uiCfg.curSprayerChoose == 1) { + lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru2.bin"); + if (gCfgItems.multiple_language) { + lv_label_set_text(labelType, preheat_menu.ext2); + lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } + else { + lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru1.bin"); + if (gCfgItems.multiple_language) { + lv_label_set_text(labelType, preheat_menu.ext1); + lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } + #else + lv_imgbtn_set_src_both(buttonType, "F:/bmp_extru1.bin"); + if (gCfgItems.multiple_language) { + lv_label_set_text(labelType, preheat_menu.ext1); + lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + #endif + } + else { + lv_imgbtn_set_src_both(buttonType, "F:/bmp_bed.bin"); + if (gCfgItems.multiple_language) { + lv_label_set_text(labelType, preheat_menu.hotbed); + lv_obj_align(labelType, buttonType, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void disp_desire_temp() { + char buf[20] = {0}; + + public_buf_l[0] = '\0'; + + if (uiCfg.curTempType == 0) { + #if DISABLED(SINGLENOZZLE) + strcat(public_buf_l, uiCfg.curSprayerChoose < 1 ? preheat_menu.ext1 : preheat_menu.ext2); + sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].celsius, (int)thermalManager.temp_hotend[uiCfg.curSprayerChoose].target); + #else + strcat(public_buf_l, preheat_menu.ext1); + sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target); + #endif + } + #if HAS_HEATED_BED + else { + strcat(public_buf_l, preheat_menu.hotbed); + sprintf(buf, preheat_menu.value_state, (int)thermalManager.temp_bed.celsius, (int)thermalManager.temp_bed.target); + } + #endif + strcat_P(public_buf_l, PSTR(": ")); + strcat(public_buf_l, buf); + lv_label_set_text(tempText1, public_buf_l); + lv_obj_align(tempText1, nullptr, LV_ALIGN_CENTER, 0, -50); +} + +void disp_step_heat() { + if (uiCfg.stepHeat == 1) { + lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step1_degree.bin"); + } + else if (uiCfg.stepHeat == 5) { + lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step5_degree.bin"); + } + else if (uiCfg.stepHeat == 10) { + lv_imgbtn_set_src_both(buttonStep, "F:/bmp_step10_degree.bin"); + } + + if (gCfgItems.multiple_language) { + if (uiCfg.stepHeat == 1) { + lv_label_set_text(labelStep, preheat_menu.step_1c); + lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if (uiCfg.stepHeat == 5) { + lv_label_set_text(labelStep, preheat_menu.step_5c); + lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + else if (uiCfg.stepHeat == 10) { + lv_label_set_text(labelStep, preheat_menu.step_10c); + lv_obj_align(labelStep, buttonStep, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + } +} + +void lv_clear_preHeat() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.h new file mode 100644 index 0000000..602f5e9 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_preHeat.h @@ -0,0 +1,36 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_preHeat(void); +extern void lv_clear_preHeat(); +extern void disp_temp_type(); +extern void disp_step_heat(); +extern void disp_desire_temp(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.cpp new file mode 100644 index 0000000..0d95f14 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.cpp @@ -0,0 +1,552 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> +//#include "../lvgl/src/lv_objx/lv_imgbtn.h" +//#include "../lvgl/src/lv_objx/lv_img.h" +//#include "../lvgl/src/lv_core/lv_disp.h" +//#include "../lvgl/src/lv_core/lv_refr.h" + +#include "../../../../sd/cardreader.h" +#include "../../../../inc/MarlinConfig.h" + +static lv_obj_t *scr; +extern lv_group_t* g; + +static lv_obj_t *buttonPageUp, *buttonPageDown, *buttonBack, + *buttonGcode[FILE_BTN_CNT], *labelPageUp[FILE_BTN_CNT], *buttonText[FILE_BTN_CNT]; + +enum { + ID_P_UP = 7, + ID_P_DOWN, + ID_P_RETURN +}; + +int8_t curDirLever = 0; +LIST_FILE list_file; +DIR_OFFSET dir_offset[10]; + +extern uint8_t public_buf[513]; +extern char public_buf_m[100]; + +uint8_t sel_id = 0; + +#if ENABLED(SDSUPPORT) + + static uint8_t search_file() { + int valid_name_cnt = 0; + //char tmp[SHORT_NEME_LEN*MAX_DIR_LEVEL+1]; + + list_file.Sd_file_cnt = 0; + //list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset; + + //root2.rewind(); + //SERIAL_ECHOLN(list_file.curDirPath); + + if (curDirLever != 0) card.cd(list_file.curDirPath); + else card.cdroot(); // while(card.cdup()); + + const uint16_t fileCnt = card.get_num_Files(); + + for (uint16_t i = 0; i < fileCnt; i++) { + if (list_file.Sd_file_cnt == list_file.Sd_file_offset) { + const uint16_t nr = SD_ORDER(i, fileCnt); + card.getfilename_sorted(nr); + + list_file.IsFolder[valid_name_cnt] = card.flag.filenameIsDir; + strcpy(list_file.file_name[valid_name_cnt], list_file.curDirPath); + strcat_P(list_file.file_name[valid_name_cnt], PSTR("/")); + strcat(list_file.file_name[valid_name_cnt], card.filename); + strcpy(list_file.long_name[valid_name_cnt], card.longest_filename()); + + valid_name_cnt++; + if (valid_name_cnt == 1) + dir_offset[curDirLever].cur_page_first_offset = list_file.Sd_file_offset; + if (valid_name_cnt >= FILE_NUM) { + dir_offset[curDirLever].cur_page_last_offset = list_file.Sd_file_offset; + list_file.Sd_file_offset++; + break; + } + list_file.Sd_file_offset++; + } + list_file.Sd_file_cnt++; + } + //card.closefile(false); + return valid_name_cnt; + } + +#endif // SDSUPPORT + +bool have_pre_pic(char *path) { + #if ENABLED(SDSUPPORT) + char *ps1;//, *ps2;//, *cur_name = strrchr(path, '/'); + card.openFileRead(path); + card.read(public_buf, 256); + ps1 = strstr((char *)public_buf, ";simage:"); + //card.read(public_buf, 512); + //ps2 = strstr((char *)public_buf, ";simage:"); + card.closefile(); + if (ps1) return true; + #endif + + return false; +} + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + uint8_t i, file_count = 0; + //switch (obj->mks_obj_id) + //{ + if (obj->mks_obj_id == ID_P_UP) { + if (dir_offset[curDirLever].curPage > 0) { + // 2015.05.19 + list_file.Sd_file_cnt = 0; + + if (dir_offset[curDirLever].cur_page_first_offset >= FILE_NUM) + list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset - FILE_NUM; + + #if ENABLED(SDSUPPORT) + file_count = search_file(); + #endif + if (file_count != 0) { + dir_offset[curDirLever].curPage--; + lv_clear_print_file(); + disp_gcode_icon(file_count); + } + } + } + else if (obj->mks_obj_id == ID_P_DOWN) { + if (dir_offset[curDirLever].cur_page_last_offset > 0) { + list_file.Sd_file_cnt = 0; + list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_last_offset + 1; + #if ENABLED(SDSUPPORT) + file_count = search_file(); + #endif + if (file_count != 0) { + dir_offset[curDirLever].curPage++; + lv_clear_print_file(); + disp_gcode_icon(file_count); + } + if (file_count < FILE_NUM) + dir_offset[curDirLever].cur_page_last_offset = 0; + } + } + else if (obj->mks_obj_id == ID_P_RETURN) { + if (curDirLever > 0) { + int8_t *ch = (int8_t *)strrchr(list_file.curDirPath, '/'); + if (ch) { + *ch = 0; + #if ENABLED(SDSUPPORT) + card.cdup(); + #endif + dir_offset[curDirLever].curPage = 0; + dir_offset[curDirLever].cur_page_first_offset = 0; + dir_offset[curDirLever].cur_page_last_offset = 0; + curDirLever--; + list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset; + #if ENABLED(SDSUPPORT) + file_count = search_file(); + #endif + lv_clear_print_file(); + disp_gcode_icon(file_count); + } + } + else { + lv_clear_print_file(); + lv_draw_ready_print(); + } + } + else { + for (i = 0; i < FILE_BTN_CNT; i++) { + if (obj->mks_obj_id == (i + 1)) { + if (list_file.file_name[i][0] != 0) { + if (list_file.IsFolder[i]) { + strcpy(list_file.curDirPath, list_file.file_name[i]); + curDirLever++; + list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset; + #if ENABLED(SDSUPPORT) + file_count = search_file(); + #endif + lv_clear_print_file(); + disp_gcode_icon(file_count); + } + else { + sel_id = i; + lv_clear_print_file(); + lv_draw_dialog(DIALOG_TYPE_PRINT_FILE); + } + break; + } + } + } + } +} + +void lv_draw_print_file(void) { + //uint8_t i; + uint8_t file_count; + + curDirLever = 0; + dir_offset[curDirLever].curPage = 0; + + list_file.Sd_file_offset = 0; + list_file.Sd_file_cnt = 0; + + ZERO(dir_offset); + ZERO(list_file.IsFolder); + ZERO(list_file.curDirPath); + + list_file.Sd_file_offset = dir_offset[curDirLever].cur_page_first_offset; + #if ENABLED(SDSUPPORT) + card.mount(); + file_count = search_file(); + #endif + disp_gcode_icon(file_count); + + //lv_obj_t *labelPageUp = lv_label_create_empty(buttonPageUp); + //lv_obj_t *labelPageDown = lv_label_create_empty(buttonPageDown); + //lv_obj_t *label_Back = lv_label_create_empty(buttonBack); + + /* + if (gCfgItems.multiple_language) { + lv_label_set_text(labelPageUp, tool_menu.preheat); + lv_obj_align(labelPageUp, buttonPageUp, LV_ALIGN_IN_BOTTOM_MID,0, BUTTON_TEXT_Y_OFFSET); + + lv_label_set_text(labelPageDown, tool_menu.extrude); + lv_obj_align(labelPageDown, buttonPageDown, LV_ALIGN_IN_BOTTOM_MID,0, BUTTON_TEXT_Y_OFFSET); + + lv_label_set_text(label_Back, common_menu.text_back); + lv_obj_align(label_Back, buttonBack, LV_ALIGN_IN_BOTTOM_MID,0, BUTTON_TEXT_Y_OFFSET); + } + */ +} +static char test_public_buf_l[(SHORT_NAME_LEN + 1) * MAX_DIR_LEVEL + strlen("S:/") + 1]; +void disp_gcode_icon(uint8_t file_num) { + uint8_t i; + + scr = lv_screen_create(PRINT_FILE_UI, ""); + + // Create image buttons + buttonPageUp = lv_imgbtn_create(scr, "F:/bmp_pageUp.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_P_UP); + buttonPageDown = lv_imgbtn_create(scr, "F:/bmp_pageDown.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + OTHER_BTN_YPIEL + INTERVAL_H, event_handler, ID_P_DOWN); + buttonBack = lv_imgbtn_create(scr, "F:/bmp_back.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + OTHER_BTN_YPIEL * 2 + INTERVAL_H * 2, event_handler, ID_P_RETURN); + + // Create labels on the image buttons + for (i = 0; i < FILE_BTN_CNT; i++) { + /* + if (seq) { + j = (FILE_BTN_CNT-1) - i; + back_flg = 1; + } + else { + j = i; + back_flg = 0; + } + */ + if (i >= file_num) break; + + #ifdef TFT35 + buttonGcode[i] = lv_imgbtn_create(scr, nullptr); + + lv_imgbtn_use_label_style(buttonGcode[i]); + lv_obj_clear_protect(buttonGcode[i], LV_PROTECT_FOLLOW); + lv_btn_set_layout(buttonGcode[i], LV_LAYOUT_OFF); + + ZERO(public_buf_m); + cutFileName((char *)list_file.long_name[i], 16, 8, (char *)public_buf_m); + + if (list_file.IsFolder[i]) { + lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), "", 0); + lv_imgbtn_set_src_both(buttonGcode[i], "F:/bmp_dir.bin"); + if (i < 3) + lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1), titleHeight); + else + lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1), BTN_Y_PIXEL + INTERVAL_H + titleHeight); + + labelPageUp[i] = lv_label_create(buttonGcode[i], public_buf_m); + lv_obj_align(labelPageUp[i], buttonGcode[i], LV_ALIGN_IN_BOTTOM_MID, 0, -5); + } + else { + if (have_pre_pic((char *)list_file.file_name[i])) { + + //lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), list_file.file_name[i], 1); + + strcpy(test_public_buf_l, "S:"); + strcat(test_public_buf_l, list_file.file_name[i]); + char *temp = strstr(test_public_buf_l, ".GCO"); + if (temp) strcpy(temp, ".bin"); + lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), test_public_buf_l, 0); + lv_imgbtn_set_src_both(buttonGcode[i], buttonGcode[i]->mks_pic_name); + if (i < 3) { + lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1) + FILE_PRE_PIC_X_OFFSET, titleHeight + FILE_PRE_PIC_Y_OFFSET); + buttonText[i] = lv_btn_create(scr, nullptr); + //lv_obj_set_event_cb(buttonText[i], event_handler); + + lv_btn_use_label_style(buttonText[i]); + lv_obj_clear_protect(buttonText[i], LV_PROTECT_FOLLOW); + lv_btn_set_layout(buttonText[i], LV_LAYOUT_OFF); + //lv_obj_set_event_cb_mks(buttonText[i], event_handler,(i+10),"", 0); + lv_obj_set_pos(buttonText[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1) + FILE_PRE_PIC_X_OFFSET, titleHeight + FILE_PRE_PIC_Y_OFFSET + 100); + lv_obj_set_size(buttonText[i], 100, 40); + } + else { + lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1) + FILE_PRE_PIC_X_OFFSET, BTN_Y_PIXEL + INTERVAL_H + titleHeight + FILE_PRE_PIC_Y_OFFSET); + buttonText[i] = lv_btn_create(scr, nullptr); + //lv_obj_set_event_cb(buttonText[i], event_handler); + + lv_btn_use_label_style(buttonText[i]); + lv_obj_clear_protect(buttonText[i], LV_PROTECT_FOLLOW); + lv_btn_set_layout(buttonText[i], LV_LAYOUT_OFF); + //lv_obj_set_event_cb_mks(buttonText[i], event_handler,(i+10),"", 0); + lv_obj_set_pos(buttonText[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1) + FILE_PRE_PIC_X_OFFSET, BTN_Y_PIXEL + INTERVAL_H + titleHeight + FILE_PRE_PIC_Y_OFFSET + 100); + lv_obj_set_size(buttonText[i], 100, 40); + } + labelPageUp[i] = lv_label_create(buttonText[i], public_buf_m); + lv_obj_align(labelPageUp[i], buttonText[i], LV_ALIGN_IN_BOTTOM_MID, 0, 0); + } + else { + lv_obj_set_event_cb_mks(buttonGcode[i], event_handler, (i + 1), "", 0); + lv_imgbtn_set_src_both(buttonGcode[i], "F:/bmp_file.bin"); + if (i < 3) + lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * i + INTERVAL_V * (i + 1), titleHeight); + else + lv_obj_set_pos(buttonGcode[i], BTN_X_PIXEL * (i - 3) + INTERVAL_V * ((i - 3) + 1), BTN_Y_PIXEL + INTERVAL_H + titleHeight); + + labelPageUp[i] = lv_label_create(buttonGcode[i], public_buf_m); + lv_obj_align(labelPageUp[i], buttonGcode[i], LV_ALIGN_IN_BOTTOM_MID, 0, -5); + } + } + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_add_obj(g, buttonGcode[i]); + #endif + + #else // !TFT35 + #endif // !TFT35 + } + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonPageUp); + lv_group_add_obj(g, buttonPageDown); + lv_group_add_obj(g, buttonBack); + } + #endif +} + +uint32_t lv_open_gcode_file(char *path) { + #if ENABLED(SDSUPPORT) + uint32_t *ps4; + uint32_t pre_sread_cnt = UINT32_MAX; + //char *cur_name; + + //cur_name = strrchr(path, '/'); + + card.openFileRead(path); + card.read(public_buf, 256); + ps4 = (uint32_t *)strstr((char *)public_buf, ";simage:"); + // Ignore the beginning message of gcode file + if (ps4) { + pre_sread_cnt = (uint32_t)ps4 - (uint32_t)((uint32_t *)(&public_buf[0])); + card.setIndex(pre_sread_cnt); + } + return pre_sread_cnt; + #endif // SDSUPPORT +} + +int ascii2dec_test(char *ascii) { + int result = 0; + if (ascii == 0) return 0; + + if (*(ascii) >= '0' && *(ascii) <= '9') + result = *(ascii) - '0'; + else if (*(ascii) >= 'a' && *(ascii) <= 'f') + result = *(ascii) - 'a' + 0x0A; + else if (*(ascii) >= 'A' && *(ascii) <= 'F') + result = *(ascii) - 'A' + 0x0A; + else + return 0; + + return result; +} + +void lv_gcode_file_read(uint8_t *data_buf) { + #if ENABLED(SDSUPPORT) + uint16_t i = 0, j = 0, k = 0; + uint16_t row_1 = 0; + bool ignore_start = true; + char temp_test[200]; + volatile uint16_t *p_index; + + watchdog_refresh(); + memset(public_buf, 0, 200); + + while (card.isFileOpen()) { + if (ignore_start) card.read(temp_test, 8); // line start -> ignore + card.read(temp_test, 200); // data + // \r;;gimage: we got the bit img, so stop here + if (temp_test[1] == ';') { + card.closefile(); + break; + } + for (i = 0; i < 200;) { + public_buf[row_1 * 200 + 100 * k + j] = (char)(ascii2dec_test(&temp_test[i]) << 4 | ascii2dec_test(&temp_test[i + 1])); + j++; + i += 2; + } + + uint16_t c = card.get(); + // check for more data or end of line (CR or LF) + if (ISEOL(c)) { + c = card.get(); // more eol? + if (!ISEOL(c)) card.setIndex(card.getIndex() - 1); + break; + } + card.setIndex(card.getIndex() - 1); + k++; + j = 0; + ignore_start = false; + if (k > 1) { + card.closefile(); + break; + } + } + #if HAS_TFT_LVGL_UI_SPI + for (i = 0; i < 200;) { + p_index = (uint16_t *)(&public_buf[i]); + + //Color = (*p_index >> 8); + //*p_index = Color | ((*p_index & 0xFF) << 8); + i += 2; + if (*p_index == 0x0000) *p_index = LV_COLOR_BACKGROUND.full; + } + #else // !HAS_TFT_LVGL_UI_SPI + for (i = 0; i < 200;) { + p_index = (uint16_t *)(&public_buf[i]); + //Color = (*p_index >> 8); + //*p_index = Color | ((*p_index & 0xFF) << 8); + i += 2; + if (*p_index == 0x0000) *p_index = LV_COLOR_BACKGROUND.full; // 0x18C3; + } + #endif // !HAS_TFT_LVGL_UI_SPI + memcpy(data_buf, public_buf, 200); + #endif // SDSUPPORT +} + +void lv_close_gcode_file() {TERN_(SDSUPPORT, card.closefile());} + +void lv_gcode_file_seek(uint32_t pos) { + TERN_(SDSUPPORT, card.setIndex(pos)); +} + +void cutFileName(char *path, int len, int bytePerLine, char *outStr) { + #if _LFN_UNICODE + TCHAR *tmpFile; + TCHAR *strIndex1 = 0, *strIndex2 = 0, *beginIndex; + TCHAR secSeg[10] = {0}; + TCHAR gFileTail[4] = {'~', '.', 'g', '\0'}; + #else + char *tmpFile; + char *strIndex1 = 0, *strIndex2 = 0, *beginIndex; + char secSeg[10] = {0}; + #endif + + if (path == 0 || len <= 3 || outStr == 0) return; + + tmpFile = path; + #if _LFN_UNICODE + strIndex1 = (WCHAR *)wcsstr((const WCHAR *)tmpFile, (const WCHAR *)'/'); + strIndex2 = (WCHAR *)wcsstr((const WCHAR *)tmpFile, (const WCHAR *)'.'); + #else + strIndex1 = (char *)strrchr(tmpFile, '/'); + strIndex2 = (char *)strrchr(tmpFile, '.'); + #endif + + beginIndex = (strIndex1 != 0 + //&& (strIndex2 != 0) && (strIndex1 < strIndex2) + ) ? strIndex1 + 1 : tmpFile; + + if (strIndex2 == 0 || (strIndex1 > strIndex2)) { // not gcode file + #if _LFN_UNICODE + if (wcslen(beginIndex) > len) + wcsncpy(outStr, beginIndex, len); + else + wcscpy(outStr, beginIndex); + #else + if ((int)strlen(beginIndex) > len) + strncpy(outStr, beginIndex, len); + else + strcpy(outStr, beginIndex); + #endif + } + else { // gcode file + if (strIndex2 - beginIndex > (len - 2)) { + #if _LFN_UNICODE + wcsncpy(outStr, (const WCHAR *)beginIndex, len - 3); + wcscat(outStr, (const WCHAR *)gFileTail); + #else + //strncpy(outStr, beginIndex, len - 3); + strncpy(outStr, beginIndex, len - 4); + strcat_P(outStr, PSTR("~.g")); + #endif + } + else { + #if _LFN_UNICODE + wcsncpy(outStr, (const WCHAR *)beginIndex, strIndex2 - beginIndex + 1); + wcscat(outStr, (const WCHAR *)&gFileTail[3]); + #else + strncpy(outStr, beginIndex, strIndex2 - beginIndex + 1); + strcat_P(outStr, PSTR("g")); + #endif + } + } + + #if _LFN_UNICODE + if (wcslen(outStr) > bytePerLine) { + wcscpy(secSeg, (const WCHAR *)&outStr[bytePerLine]); + outStr[bytePerLine] = '\n'; + outStr[bytePerLine + 1] = '\0'; + wcscat(outStr, (const WCHAR *)secSeg); + } + #else + if ((int)strlen(outStr) > bytePerLine) { + strcpy(secSeg, &outStr[bytePerLine]); + outStr[bytePerLine] = '\n'; + outStr[bytePerLine + 1] = '\0'; + strcat(outStr, secSeg); + } + else { + strcat_P(outStr, PSTR("\n")); + } + #endif +} + +void lv_clear_print_file() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.h new file mode 100644 index 0000000..126dab0 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_print_file.h @@ -0,0 +1,64 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +typedef struct { + int cur_page_first_offset; + int cur_page_last_offset; + int curPage; +} DIR_OFFSET; +extern DIR_OFFSET dir_offset[10]; + +#define FILE_NUM 6 +#define SHORT_NAME_LEN 13 +#define NAME_CUT_LEN 23 + +#define MAX_DIR_LEVEL 10 + +typedef struct { + char file_name[FILE_NUM][(SHORT_NAME_LEN + 1) * MAX_DIR_LEVEL + 1]; + char curDirPath[(SHORT_NAME_LEN + 1) * MAX_DIR_LEVEL + 1]; + char long_name[FILE_NUM][SHORT_NAME_LEN * 2 + 1]; + bool IsFolder[FILE_NUM]; + char Sd_file_cnt; + char sd_file_index; + char Sd_file_offset; +} LIST_FILE; +extern LIST_FILE list_file; + +extern void disp_gcode_icon(uint8_t file_num); +extern void lv_draw_print_file(void); +extern uint32_t lv_open_gcode_file(char *path); +extern void lv_gcode_file_read(uint8_t *data_buf); +extern void lv_close_gcode_file(); +extern void cutFileName(char *path, int len, int bytePerLine, char *outStr); +extern int ascii2dec_test(char *ascii); +extern void lv_clear_print_file(); +extern void lv_gcode_file_seek(uint32_t pos); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.cpp new file mode 100644 index 0000000..5a474ce --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.cpp @@ -0,0 +1,290 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../MarlinCore.h" // for marlin_state +#include "../../../../module/temperature.h" +#include "../../../../module/motion.h" +#include "../../../../sd/cardreader.h" +#include "../../../../gcode/queue.h" +#include "../../../../gcode/gcode.h" +#include "../../../../inc/MarlinConfig.h" + +#if ENABLED(POWER_LOSS_RECOVERY) + #include "../../../../feature/powerloss.h" +#endif + +#if BOTH(LCD_SET_PROGRESS_MANUALLY, USE_M73_REMAINING_TIME) + #include "../../../marlinui.h" +#endif + +extern lv_group_t *g; +static lv_obj_t *scr; +static lv_obj_t *labelExt1, *labelFan, *labelZpos, *labelTime; +static lv_obj_t *labelPause, *labelStop, *labelOperat; +static lv_obj_t *bar1, *bar1ValueText; +static lv_obj_t *buttonPause, *buttonOperat, *buttonStop; + +#if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER + static lv_obj_t *labelExt2; +#endif + +#if HAS_HEATED_BED + static lv_obj_t* labelBed; +#endif + +enum { + ID_PAUSE = 1, + ID_STOP, + ID_OPTION +}; + +bool once_flag; // = false +extern bool flash_preview_begin, default_preview_flg, gcode_preview_over; +extern uint32_t To_pre_view; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + if (gcode_preview_over) return; + switch (obj->mks_obj_id) { + case ID_PAUSE: + if (uiCfg.print_state == WORKING) { + #if ENABLED(SDSUPPORT) + card.pauseSDPrint(); + stop_print_time(); + uiCfg.print_state = PAUSING; + #endif + lv_imgbtn_set_src_both(buttonPause, "F:/bmp_resume.bin"); + lv_label_set_text(labelPause, printing_menu.resume); + lv_obj_align(labelPause, buttonPause, LV_ALIGN_CENTER, 30, 0); + } + else if (uiCfg.print_state == PAUSED) { + uiCfg.print_state = RESUMING; + lv_imgbtn_set_src_both(obj, "F:/bmp_pause.bin"); + lv_label_set_text(labelPause, printing_menu.pause); + lv_obj_align(labelPause, buttonPause, LV_ALIGN_CENTER, 30, 0); + } + #if ENABLED(POWER_LOSS_RECOVERY) + else if (uiCfg.print_state == REPRINTING) { + uiCfg.print_state = REPRINTED; + lv_imgbtn_set_src_both(obj, "F:/bmp_pause.bin"); + lv_label_set_text(labelPause, printing_menu.pause); + lv_obj_align(labelPause, buttonPause, LV_ALIGN_CENTER, 30, 0); + print_time.minutes = recovery.info.print_job_elapsed / 60; + print_time.seconds = recovery.info.print_job_elapsed % 60; + print_time.hours = print_time.minutes / 60; + } + #endif + break; + + case ID_STOP: + lv_clear_printing(); + lv_draw_dialog(DIALOG_TYPE_STOP); + break; + case ID_OPTION: + lv_clear_printing(); + lv_draw_operation(); + break; + } +} + +void lv_draw_printing(void) { + disp_state_stack._disp_index = 0; + ZERO(disp_state_stack._disp_state); + scr = lv_screen_create(PRINTING_UI); + + // Create image buttons + lv_obj_t *buttonExt1 = lv_img_create(scr, nullptr); + lv_img_set_src(buttonExt1, "F:/bmp_ext1_state.bin"); + lv_obj_set_pos(buttonExt1, 205, 136); + + #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER + lv_obj_t *buttonExt2 = lv_img_create(scr, nullptr); + lv_img_set_src(buttonExt2, "F:/bmp_ext2_state.bin"); + lv_obj_set_pos(buttonExt2, 350, 136); + #endif + + #if HAS_HEATED_BED + lv_obj_t *buttonBedstate = lv_img_create(scr, nullptr); + lv_img_set_src(buttonBedstate, "F:/bmp_bed_state.bin"); + lv_obj_set_pos(buttonBedstate, 205, 186); + #endif + + lv_obj_t *buttonFanstate = lv_img_create(scr, nullptr); + lv_img_set_src(buttonFanstate, "F:/bmp_fan_state.bin"); + lv_obj_set_pos(buttonFanstate, 350, 186); + + lv_obj_t *buttonTime = lv_img_create(scr, nullptr); + lv_img_set_src(buttonTime, "F:/bmp_time_state.bin"); + lv_obj_set_pos(buttonTime, 205, 86); + + lv_obj_t *buttonZpos = lv_img_create(scr, nullptr); + lv_img_set_src(buttonZpos, "F:/bmp_zpos_state.bin"); + lv_obj_set_pos(buttonZpos, 350, 86); + + buttonPause = lv_imgbtn_create(scr, uiCfg.print_state == WORKING ? "F:/bmp_pause.bin" : "F:/bmp_resume.bin", 5, 240, event_handler, ID_PAUSE); + buttonStop = lv_imgbtn_create(scr, "F:/bmp_stop.bin", 165, 240, event_handler, ID_STOP); + buttonOperat = lv_imgbtn_create(scr, "F:/bmp_operate.bin", 325, 240, event_handler, ID_OPTION); + + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonPause); + lv_group_add_obj(g, buttonStop); + lv_group_add_obj(g, buttonOperat); + } + #endif + + labelExt1 = lv_label_create(scr, 250, 146, nullptr); + + #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER + labelExt2 = lv_label_create(scr, 395, 146, nullptr); + #endif + + #if HAS_HEATED_BED + labelBed = lv_label_create(scr, 250, 196, nullptr); + #endif + + labelFan = lv_label_create(scr, 395, 196, nullptr); + labelTime = lv_label_create(scr, 250, 96, nullptr); + labelZpos = lv_label_create(scr, 395, 96, nullptr); + + labelPause = lv_label_create_empty(buttonPause); + labelStop = lv_label_create_empty(buttonStop); + labelOperat = lv_label_create_empty(buttonOperat); + + if (gCfgItems.multiple_language) { + lv_label_set_text(labelPause, uiCfg.print_state == WORKING ? printing_menu.pause : printing_menu.resume); + lv_obj_align(labelPause, buttonPause, LV_ALIGN_CENTER, 20, 0); + + lv_label_set_text(labelStop, printing_menu.stop); + lv_obj_align(labelStop, buttonStop, LV_ALIGN_CENTER, 20, 0); + + lv_label_set_text(labelOperat, printing_menu.option); + lv_obj_align(labelOperat, buttonOperat, LV_ALIGN_CENTER, 20, 0); + } + + bar1 = lv_bar_create(scr, nullptr); + lv_obj_set_pos(bar1, 205, 36); + lv_obj_set_size(bar1, 270, 40); + lv_bar_set_style(bar1, LV_BAR_STYLE_INDIC, &lv_bar_style_indic); + lv_bar_set_anim_time(bar1, 1000); + lv_bar_set_value(bar1, 0, LV_ANIM_ON); + bar1ValueText = lv_label_create_empty(bar1); + lv_label_set_text(bar1ValueText,"0%"); + lv_obj_align(bar1ValueText, bar1, LV_ALIGN_CENTER, 0, 0); + + disp_ext_temp(); + disp_bed_temp(); + disp_fan_speed(); + disp_print_time(); + disp_fan_Zpos(); +} + +void disp_ext_temp() { + sprintf(public_buf_l, printing_menu.temp1, (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target); + lv_label_set_text(labelExt1, public_buf_l); + + #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER + sprintf(public_buf_l, printing_menu.temp1, (int)thermalManager.temp_hotend[1].celsius, (int)thermalManager.temp_hotend[1].target); + lv_label_set_text(labelExt2, public_buf_l); + #endif +} + +void disp_bed_temp() { + #if HAS_HEATED_BED + sprintf(public_buf_l, printing_menu.bed_temp, (int)thermalManager.temp_bed.celsius, (int)thermalManager.temp_bed.target); + lv_label_set_text(labelBed, public_buf_l); + #endif +} + +void disp_fan_speed() { + sprintf_P(public_buf_l, PSTR("%3d"), thermalManager.fan_speed[0]); + lv_label_set_text(labelFan, public_buf_l); +} + +void disp_print_time() { + #if BOTH(LCD_SET_PROGRESS_MANUALLY, USE_M73_REMAINING_TIME) + const uint32_t r = ui.get_remaining_time(); + sprintf_P(public_buf_l, PSTR("%02d:%02d R"), r / 3600, (r % 3600) / 60); + #else + sprintf_P(public_buf_l, PSTR("%d%d:%d%d:%d%d"), print_time.hours / 10, print_time.hours % 10, print_time.minutes / 10, print_time.minutes % 10, print_time.seconds / 10, print_time.seconds % 10); + #endif + lv_label_set_text(labelTime, public_buf_l); +} + +void disp_fan_Zpos() { + char str_1[16]; + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(current_position[Z_AXIS], 1, 3, str_1)); + lv_label_set_text(labelZpos, public_buf_l); +} + +void reset_print_time() { + print_time.hours = 0; + print_time.minutes = 0; + print_time.seconds = 0; + print_time.ms_10 = 0; +} + +void start_print_time() { print_time.start = 1; } + +void stop_print_time() { print_time.start = 0; } + +void setProBarRate() { + int rate; + volatile long long rate_tmp_r; + + if (!gCfgItems.from_flash_pic) { + #if ENABLED(SDSUPPORT) + rate_tmp_r = (long long)card.getIndex() * 100; + #endif + rate = rate_tmp_r / gCfgItems.curFilesize; + } + else { + #if ENABLED(SDSUPPORT) + rate_tmp_r = (long long)card.getIndex(); + #endif + rate = (rate_tmp_r - (PREVIEW_SIZE + To_pre_view)) * 100 / (gCfgItems.curFilesize - (PREVIEW_SIZE + To_pre_view)); + } + + if (rate <= 0) return; + + if (disp_state == PRINTING_UI) { + lv_bar_set_value(bar1, rate, LV_ANIM_ON); + sprintf_P(public_buf_l, "%d%%", rate); + lv_label_set_text(bar1ValueText,public_buf_l); + lv_obj_align(bar1ValueText, bar1, LV_ALIGN_CENTER, 0, 0); + } +} + +void lv_clear_printing() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.h new file mode 100644 index 0000000..d6da1a1 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_printing.h @@ -0,0 +1,53 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +enum { + IDLE, + WORKING, + PAUSING, + PAUSED, + REPRINTING, + REPRINTED, + RESUMING, + STOP +}; + +extern void lv_draw_printing(void); +extern void lv_clear_printing(); +extern void disp_ext_temp(); +extern void disp_bed_temp(); +extern void disp_fan_speed(); +extern void disp_print_time(); +extern void disp_fan_Zpos(); +extern void reset_print_time(); +extern void start_print_time(); +extern void stop_print_time(); +extern void setProBarRate(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.cpp new file mode 100644 index 0000000..de4e41c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.cpp @@ -0,0 +1,220 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ready_print.h" +#include "draw_tool.h" +#include <lv_conf.h> +#include "tft_lvgl_configuration.h" +#include "mks_hardware_test.h" +#include "draw_ui.h" + +#include <lvgl.h> + +#include "../../../../module/temperature.h" +#include "../../../../inc/MarlinConfig.h" + +#if ENABLED(TOUCH_SCREEN_CALIBRATION) + #include "../../../tft_io/touch_calibration.h" + #include "draw_touch_calibration.h" +#endif + +#include <stdio.h> + +extern lv_group_t* g; +static lv_obj_t *scr; +#if ENABLED(MKS_TEST) + uint8_t curent_disp_ui = 0; +#endif + +enum { + ID_TOOL = 1, + ID_SET, + ID_PRINT +}; +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + lv_clear_ready_print(); + + switch (obj->mks_obj_id) { + case ID_TOOL: + lv_draw_tool(); + break; + case ID_SET: + lv_draw_set(); + break; + case ID_PRINT: + lv_draw_print_file(); + break; + } +} + +lv_obj_t *limit_info, *det_info; +lv_obj_t *tmc_state_info; +lv_style_t limit_style, det_style, tmc_state_style; +void disp_Limit_ok() { + limit_style.text.color.full = 0xFFFF; + lv_obj_set_style(limit_info, &limit_style); + lv_label_set_text(limit_info, "Limit:ok"); +} +void disp_Limit_error() { + limit_style.text.color.full = 0xF800; + lv_obj_set_style(limit_info, &limit_style); + lv_label_set_text(limit_info, "Limit:error"); +} + +void disp_det_ok() { + det_style.text.color.full = 0xFFFF; + lv_obj_set_style(det_info, &det_style); + lv_label_set_text(det_info, "det:ok"); +} +void disp_det_error() { + det_style.text.color.full = 0xF800; + lv_obj_set_style(det_info, &det_style); + lv_label_set_text(det_info, "det:error"); +} + +void disp_tmc_ok() { + tmc_state_style.text.color.full = 0xFFFF; + lv_obj_set_style(tmc_state_info, &tmc_state_style); + lv_label_set_text(tmc_state_info, "TMC CONNECTION OK"); +} +void disp_tmc_error() { + tmc_state_style.text.color.full = 0xF800; + lv_obj_set_style(tmc_state_info, &tmc_state_style); + lv_label_set_text(tmc_state_info, "TMC CONNECTION ERROR"); +} + +lv_obj_t *e1, *e2, *e3, *bed; +void mks_disp_test() { + char buf[30] = {0}; + sprintf_P(buf, PSTR("e1:%d"), (int)thermalManager.temp_hotend[0].celsius); + lv_label_set_text(e1, buf); + #if HAS_MULTI_HOTEND + sprintf_P(buf, PSTR("e2:%d"), (int)thermalManager.temp_hotend[1].celsius); + lv_label_set_text(e2, buf); + #endif + #if HAS_HEATED_BED + sprintf_P(buf, PSTR("bed:%d"), (int)thermalManager.temp_bed.celsius); + lv_label_set_text(bed, buf); + #endif +} + +void lv_draw_ready_print(void) { + char buf[30] = {0}; + lv_obj_t *buttonTool; + + disp_state_stack._disp_index = 0; + ZERO(disp_state_stack._disp_state); + scr = lv_screen_create(PRINT_READY_UI, ""); + + if (mks_test_flag == 0x1E) { + // Create image buttons + buttonTool = lv_imgbtn_create(scr, "F:/bmp_tool.bin", event_handler, ID_TOOL); + + lv_obj_set_pos(buttonTool, 360, 180); + + lv_obj_t *label_tool = lv_label_create_empty(buttonTool); + if (gCfgItems.multiple_language) { + lv_label_set_text(label_tool, main_menu.tool); + lv_obj_align(label_tool, buttonTool, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + + #if 1 + e1 = lv_label_create_empty(scr); + lv_obj_set_pos(e1, 20, 20); + sprintf_P(buf, PSTR("e1: %d"), (int)thermalManager.temp_hotend[0].celsius); + lv_label_set_text(e1, buf); + #if HAS_MULTI_HOTEND + e2 = lv_label_create_empty(scr); + lv_obj_set_pos(e2, 20, 45); + sprintf_P(buf, PSTR("e1: %d"), (int)thermalManager.temp_hotend[1].celsius); + lv_label_set_text(e2, buf); + #endif + + #if HAS_HEATED_BED + bed = lv_label_create_empty(scr); + lv_obj_set_pos(bed, 20, 95); + sprintf_P(buf, PSTR("bed: %d"), (int)thermalManager.temp_bed.celsius); + lv_label_set_text(bed, buf); + #endif + + limit_info = lv_label_create_empty(scr); + + lv_style_copy(&limit_style, &lv_style_scr); + limit_style.body.main_color.full = 0X0000; + limit_style.body.grad_color.full = 0X0000; + limit_style.text.color.full = 0Xffff; + lv_obj_set_style(limit_info, &limit_style); + + lv_obj_set_pos(limit_info, 20, 120); + lv_label_set_text(limit_info, " "); + + det_info = lv_label_create_empty(scr); + + lv_style_copy(&det_style, &lv_style_scr); + det_style.body.main_color.full = 0X0000; + det_style.body.grad_color.full = 0X0000; + det_style.text.color.full = 0Xffff; + lv_obj_set_style(det_info, &det_style); + + lv_obj_set_pos(det_info, 20, 145); + lv_label_set_text(det_info, " "); + + tmc_state_info = lv_label_create_empty(scr); + + lv_style_copy(&tmc_state_style, &lv_style_scr); + tmc_state_style.body.main_color.full = 0X0000; + tmc_state_style.body.grad_color.full = 0X0000; + tmc_state_style.text.color.full = 0Xffff; + lv_obj_set_style(tmc_state_info, &tmc_state_style); + + lv_obj_set_pos(tmc_state_info, 20, 170); + lv_label_set_text(tmc_state_info, " "); + #endif // if 1 + + } + else { + lv_big_button_create(scr, "F:/bmp_tool.bin", main_menu.tool, 20, 90, event_handler, ID_TOOL); + lv_big_button_create(scr, "F:/bmp_set.bin", main_menu.set, 180, 90, event_handler, ID_SET); + lv_big_button_create(scr, "F:/bmp_printing.bin", main_menu.print, 340, 90, event_handler, ID_PRINT); + } + + #if ENABLED(TOUCH_SCREEN_CALIBRATION) + // If calibration is required, let's trigger it now, handles the case when there is default value in configuration files + if (!touch_calibration.calibration_loaded()) { + lv_clear_ready_print(); + lv_draw_touch_calibration_screen(); + } + #endif +} + +void lv_clear_ready_print() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.h new file mode 100644 index 0000000..7d17fb2 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ready_print.h @@ -0,0 +1,40 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_ready_print(void); +extern void mks_disp_test(); +extern void disp_Limit_ok(); +extern void disp_Limit_error(); +extern void disp_det_error(); +extern void disp_det_ok(); +extern void disp_tmc_ok(); +extern void disp_tmc_error(); +extern void lv_clear_ready_print(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_set.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_set.cpp new file mode 100644 index 0000000..328f795 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_set.cpp @@ -0,0 +1,134 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ready_print.h" +#include "draw_set.h" +#include "draw_ui.h" +#include <lv_conf.h> + +#include "pic_manager.h" + +#include "../../../../gcode/queue.h" +#include "../../../../inc/MarlinConfig.h" + +#if HAS_SUICIDE + #include "../../../../MarlinCore.h" +#endif + +static lv_obj_t *scr; +extern lv_group_t* g; + +enum { + ID_S_WIFI = 1, + ID_S_FAN, + ID_S_ABOUT, + ID_S_CONTINUE, + ID_S_MOTOR_OFF, + ID_S_LANGUAGE, + ID_S_MACHINE_PARA, + ID_S_EEPROM_SET, + ID_S_RETURN +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + if(obj->mks_obj_id != ID_S_MOTOR_OFF) lv_clear_set(); + switch (obj->mks_obj_id) { + case ID_S_FAN: + lv_draw_fan(); + break; + case ID_S_ABOUT: + lv_draw_about(); + break; + case ID_S_CONTINUE: return; + case ID_S_MOTOR_OFF: + TERN(HAS_SUICIDE, suicide(), queue.enqueue_now_P(PSTR("M84"))); + return; + case ID_S_LANGUAGE: + lv_draw_language(); + break; + case ID_S_MACHINE_PARA: + lv_draw_machine_para(); + break; + case ID_S_EEPROM_SET: + lv_draw_eeprom_settings(); + break; + case ID_S_RETURN: + lv_draw_ready_print(); + break; + + #if ENABLED(MKS_WIFI_MODULE) + case ID_S_WIFI: + if (gCfgItems.wifi_mode_sel == STA_MODEL) { + if (wifi_link_state == WIFI_CONNECTED) { + last_disp_state = SET_UI; + lv_draw_wifi(); + } + else { + if (uiCfg.command_send == 1) { + uint8_t cmd_wifi_list[] = { 0xA5, 0x07, 0x00, 0x00, 0xFC }; + raw_send_to_wifi(cmd_wifi_list, COUNT(cmd_wifi_list)); + last_disp_state = SET_UI; + lv_draw_wifi_list(); + } + else { + last_disp_state = SET_UI; + lv_draw_dialog(DIALOG_WIFI_ENABLE_TIPS); + } + } + } + else { + last_disp_state = SET_UI; + lv_draw_wifi(); + } + break; + #endif + } +} + +void lv_draw_set(void) { + scr = lv_screen_create(SET_UI); + lv_big_button_create(scr, "F:/bmp_eeprom_settings.bin", set_menu.eepromSet, INTERVAL_V, titleHeight, event_handler, ID_S_EEPROM_SET); + lv_big_button_create(scr, "F:/bmp_fan.bin", set_menu.fan, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_S_FAN); + lv_big_button_create(scr, "F:/bmp_about.bin", set_menu.about, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_S_ABOUT); + lv_big_button_create(scr, ENABLED(HAS_SUICIDE) ? "F:/bmp_manual_off.bin" : "F:/bmp_function1.bin", set_menu.TERN(HAS_SUICIDE, shutdown, motoroff), BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_S_MOTOR_OFF); + lv_big_button_create(scr, "F:/bmp_machine_para.bin", set_menu.machine_para, INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_MACHINE_PARA); + #if HAS_LANG_SELECT_SCREEN + lv_big_button_create(scr, "F:/bmp_language.bin", set_menu.language, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_LANGUAGE); + #endif + #if ENABLED(MKS_WIFI_MODULE) + lv_big_button_create(scr, "F:/bmp_wifi.bin", set_menu.wifi, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_WIFI); + #endif + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_S_RETURN); +} + +void lv_clear_set() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_set.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_set.h new file mode 100644 index 0000000..eed0c6c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_set.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_set(void); +extern void lv_clear_set(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.cpp new file mode 100644 index 0000000..e3f26d8 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.cpp @@ -0,0 +1,115 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/planner.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_STEP_RETURN = 1, + ID_STEP_X, + ID_STEP_Y, + ID_STEP_Z, + ID_STEP_E0, + ID_STEP_E1, + ID_STEP_DOWN, + ID_STEP_UP +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + lv_clear_step_settings(); + switch (obj->mks_obj_id) { + case ID_STEP_RETURN: + uiCfg.para_ui_page = 0; + lv_draw_return_ui(); + return; + case ID_STEP_X: + value = Xstep; + break; + case ID_STEP_Y: + value = Ystep; + break; + case ID_STEP_Z: + value = Zstep; + break; + case ID_STEP_E0: + value = E0step; + break; + case ID_STEP_E1: + value = E1step; + break; + case ID_STEP_UP: + uiCfg.para_ui_page = 0; + lv_draw_step_settings(); + return; + case ID_STEP_DOWN: + uiCfg.para_ui_page = 1; + lv_draw_step_settings(); + return; + } + lv_draw_number_key(); +} + +void lv_draw_step_settings(void) { + char str_1[16]; + scr = lv_screen_create(STEPS_UI, machine_menu.StepsConfTitle); + + if (uiCfg.para_ui_page != 1) { + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[X_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.X_Steps, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_STEP_X, 0, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[Y_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.Y_Steps, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_STEP_Y, 1, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[Z_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.Z_Steps, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_STEP_Z, 2, public_buf_l); + + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[E_AXIS], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.E0_Steps, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_STEP_E0, 3, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_STEP_DOWN); + } + else { + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(planner.settings.axis_steps_per_mm[E_AXIS_N(1)], 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.E1_Steps, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_STEP_E1, 0, public_buf_l); + lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_STEP_UP); + } + lv_screen_menu_item_return(scr, event_handler, ID_STEP_RETURN); +} + +void lv_clear_step_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.h new file mode 100644 index 0000000..b7eaeb4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_step_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_step_settings(void); +extern void lv_clear_step_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.cpp new file mode 100644 index 0000000..acea430 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.cpp @@ -0,0 +1,156 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if BOTH(HAS_TFT_LVGL_UI, HAS_TRINAMIC_CONFIG) + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/stepper/indirection.h" +#include "../../../../feature/tmc_util.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_TMC_CURRENT_RETURN = 1, + ID_TMC_CURRENT_X, + ID_TMC_CURRENT_Y, + ID_TMC_CURRENT_Z, + ID_TMC_CURRENT_E0, + ID_TMC_CURRENT_E1, + ID_TMC_CURRENT_DOWN, + ID_TMC_CURRENT_UP +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + lv_clear_tmc_current_settings(); + switch (obj->mks_obj_id) { + case ID_TMC_CURRENT_RETURN: + uiCfg.para_ui_page = 0; + lv_draw_return_ui(); + return; + #if AXIS_IS_TMC(X) + case ID_TMC_CURRENT_X: + value = Xcurrent; + break; + #endif + #if AXIS_IS_TMC(Y) + case ID_TMC_CURRENT_Y: + value = Ycurrent; + break; + #endif + #if AXIS_IS_TMC(Z) + case ID_TMC_CURRENT_Z: + value = Zcurrent; + break; + #endif + #if AXIS_IS_TMC(E0) + case ID_TMC_CURRENT_E0: + value = E0current; + break; + #endif + #if AXIS_IS_TMC(E1) + case ID_TMC_CURRENT_E1: + value = E1current; + break; + #endif + + case ID_TMC_CURRENT_UP: + uiCfg.para_ui_page = 0; + lv_draw_tmc_current_settings(); + return; + case ID_TMC_CURRENT_DOWN: + uiCfg.para_ui_page = 1; + lv_draw_tmc_current_settings(); + return; + } + lv_draw_number_key(); + +} + +void lv_draw_tmc_current_settings(void) { + scr = lv_screen_create(TMC_CURRENT_UI, machine_menu.TmcCurrentConfTitle); + + float milliamps; + char str_1[16]; + if (uiCfg.para_ui_page != 1) { + #if AXIS_IS_TMC(X) + milliamps = stepperX.getMilliamps(); + #else + milliamps = -1; + #endif + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.X_Current, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_CURRENT_X, 0, public_buf_l); + + #if AXIS_IS_TMC(Y) + milliamps = stepperY.getMilliamps(); + #else + milliamps = -1; + #endif + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.Y_Current, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_TMC_CURRENT_Y, 1, public_buf_l); + + #if AXIS_IS_TMC(Z) + milliamps = stepperZ.getMilliamps(); + #else + milliamps = -1; + #endif + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.Z_Current, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_TMC_CURRENT_Z, 2, public_buf_l); + + #if AXIS_IS_TMC(E0) + milliamps = stepperE0.getMilliamps(); + #else + milliamps = -1; + #endif + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.E0_Current, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_TMC_CURRENT_E0, 3, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_TMC_CURRENT_DOWN); + } + else { + #if AXIS_IS_TMC(E1) + milliamps = stepperE1.getMilliamps(); + #else + milliamps = -1; + #endif + sprintf_P(public_buf_l, PSTR("%s"), dtostrf(milliamps, 1, 1, str_1)); + lv_screen_menu_item_1_edit(scr, machine_menu.E1_Current, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_CURRENT_E1, 0, public_buf_l); + + lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_TMC_CURRENT_UP); + } + + lv_screen_menu_item_return(scr, event_handler, ID_TMC_CURRENT_RETURN); +} + +void lv_clear_tmc_current_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI && HAS_TRINAMIC_CONFIG diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.h new file mode 100644 index 0000000..927db37 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_current_settings.h @@ -0,0 +1,34 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_tmc_current_settings(void); +extern void lv_clear_tmc_current_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif + diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.cpp new file mode 100644 index 0000000..5ba7fe3 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.cpp @@ -0,0 +1,154 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if BOTH(HAS_TFT_LVGL_UI, HAS_STEALTHCHOP) + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../module/stepper/indirection.h" +#include "../../../../feature/tmc_util.h" +#include "../../../../inc/MarlinConfig.h" + +#if ENABLED(EEPROM_SETTINGS) + #include "../../../../module/settings.h" +#endif + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_TMC_MODE_RETURN = 1, + ID_TMC_MODE_X, + ID_TMC_MODE_Y, + ID_TMC_MODE_Z, + ID_TMC_MODE_E0, + ID_TMC_MODE_E1, + ID_TMC_MODE_DOWN, + ID_TMC_MODE_UP +}; + +static lv_obj_t *buttonXState = nullptr, *buttonYState = nullptr, *buttonZState = nullptr, *buttonE0State = nullptr; + +static lv_obj_t *buttonE1State = nullptr; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + + auto toggle_chop = [&](auto &stepper, auto &button) { + const bool isena = stepper.toggle_stepping_mode(); + lv_screen_menu_item_onoff_update(button, isena); + TERN_(EEPROM_SETTINGS, (void)settings.save()); + }; + + switch (obj->mks_obj_id) { + case ID_TMC_MODE_RETURN: + uiCfg.para_ui_page = 0; + lv_clear_tmc_step_mode_settings(); + lv_draw_return_ui(); + break; + + #if AXIS_HAS_STEALTHCHOP(X) + case ID_TMC_MODE_X: + toggle_chop(stepperX, buttonXState); + break; + #endif + #if AXIS_HAS_STEALTHCHOP(Y) + case ID_TMC_MODE_Y: + toggle_chop(stepperY, buttonYState); + break; + #endif + #if AXIS_HAS_STEALTHCHOP(Z) + case ID_TMC_MODE_Z: + toggle_chop(stepperZ, buttonZState); + break; + #endif + #if AXIS_HAS_STEALTHCHOP(E0) + case ID_TMC_MODE_E0: + toggle_chop(stepperE0, buttonE0State); + break; + #endif + #if AXIS_HAS_STEALTHCHOP(E1) + case ID_TMC_MODE_E1: + toggle_chop(stepperE1, buttonE1State); + break; + #endif + + case ID_TMC_MODE_UP: + uiCfg.para_ui_page = 0; + lv_clear_tmc_step_mode_settings(); + lv_draw_tmc_step_mode_settings(); + break; + case ID_TMC_MODE_DOWN: + uiCfg.para_ui_page = 1; + lv_clear_tmc_step_mode_settings(); + lv_draw_tmc_step_mode_settings(); + break; + } +} + +void lv_draw_tmc_step_mode_settings(void) { + buttonXState = buttonYState = buttonZState = buttonE0State = buttonE1State = nullptr; + + scr = lv_screen_create(TMC_MODE_UI, machine_menu.TmcStepModeConfTitle); + + bool stealth_X = false, stealth_Y = false, stealth_Z = false, stealth_E0 = false, stealth_E1 = false; + #if AXIS_HAS_STEALTHCHOP(X) + stealth_X = stepperX.get_stealthChop(); + #endif + #if AXIS_HAS_STEALTHCHOP(Y) + stealth_Y = stepperY.get_stealthChop(); + #endif + #if AXIS_HAS_STEALTHCHOP(Z) + stealth_Z = stepperZ.get_stealthChop(); + #endif + #if AXIS_HAS_STEALTHCHOP(E0) + stealth_E0 = stepperE0.get_stealthChop(); + #endif + #if AXIS_HAS_STEALTHCHOP(E1) + stealth_E1 = stepperE1.get_stealthChop(); + #endif + + if (uiCfg.para_ui_page != 1) { + buttonXState = lv_screen_menu_item_onoff(scr, machine_menu.X_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_MODE_X, 0, stealth_X); + buttonYState = lv_screen_menu_item_onoff(scr, machine_menu.Y_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_TMC_MODE_Y, 1, stealth_Y); + buttonZState = lv_screen_menu_item_onoff(scr, machine_menu.Z_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_TMC_MODE_Z, 2, stealth_Z); + buttonE0State = lv_screen_menu_item_onoff(scr, machine_menu.E0_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_TMC_MODE_E0, 2, stealth_E0); + lv_screen_menu_item_turn_page(scr, machine_menu.next, event_handler, ID_TMC_MODE_DOWN); + } + else { + buttonE1State = lv_screen_menu_item_onoff(scr, machine_menu.E1_StepMode, PARA_UI_POS_X, PARA_UI_POS_Y, event_handler, ID_TMC_MODE_E1, 0, stealth_E1); + lv_screen_menu_item_turn_page(scr, machine_menu.previous, event_handler, ID_TMC_MODE_UP); + } + + lv_screen_menu_item_return(scr, event_handler, ID_TMC_MODE_RETURN); +} + +void lv_clear_tmc_step_mode_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI && HAS_STEALTHCHOP diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.h new file mode 100644 index 0000000..35c57ab --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tmc_step_mode_settings.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_tmc_step_mode_settings(void); +extern void lv_clear_tmc_step_mode_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.cpp new file mode 100644 index 0000000..559d166 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.cpp @@ -0,0 +1,113 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../gcode/queue.h" +#include "../../../../module/temperature.h" +#include "../../../../inc/MarlinConfig.h" + +extern lv_group_t *g; +static lv_obj_t *scr; + +enum { + ID_T_PRE_HEAT = 1, + ID_T_EXTRUCT, + ID_T_MOV, + ID_T_HOME, + ID_T_LEVELING, + ID_T_FILAMENT, + ID_T_MORE, + ID_T_RETURN +}; + +#if ENABLED(MKS_TEST) + extern uint8_t curent_disp_ui; +#endif + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + #if ENABLED(AUTO_BED_LEVELING_BILINEAR) + bool clear = (obj->mks_obj_id != ID_T_LEVELING); + #else + constexpr bool clear = true; + #endif + if (clear) lv_clear_tool(); + switch (obj->mks_obj_id) { + case ID_T_PRE_HEAT: + lv_draw_preHeat(); + break; + case ID_T_EXTRUCT: + lv_draw_extrusion(); + break; + case ID_T_MOV: + lv_draw_move_motor(); + break; + case ID_T_HOME: + lv_draw_home(); + break; + case ID_T_LEVELING: + #if ENABLED(AUTO_BED_LEVELING_BILINEAR) + get_gcode_command(AUTO_LEVELING_COMMAND_ADDR,(uint8_t *)public_buf_m); + public_buf_m[sizeof(public_buf_m)-1] = 0; + queue.inject_P(PSTR(public_buf_m)); + #else + uiCfg.leveling_first_time = 1; + lv_draw_manualLevel(); + #endif + break; + case ID_T_FILAMENT: + uiCfg.desireSprayerTempBak = thermalManager.temp_hotend[uiCfg.curSprayerChoose].target; + lv_draw_filament_change(); + break; + case ID_T_MORE: lv_draw_more(); break; + case ID_T_RETURN: + TERN_(MKS_TEST, curent_disp_ui = 1); + lv_draw_ready_print(); + break; + } +} + +void lv_draw_tool(void) { + scr = lv_screen_create(TOOL_UI); + lv_big_button_create(scr, "F:/bmp_preHeat.bin", tool_menu.preheat, INTERVAL_V, titleHeight, event_handler, ID_T_PRE_HEAT); + lv_big_button_create(scr, "F:/bmp_extruct.bin", tool_menu.extrude, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_T_EXTRUCT); + lv_big_button_create(scr, "F:/bmp_mov.bin", tool_menu.move, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_T_MOV); + lv_big_button_create(scr, "F:/bmp_zero.bin", tool_menu.home, BTN_X_PIXEL * 3 + INTERVAL_V * 4, titleHeight, event_handler, ID_T_HOME); + lv_big_button_create(scr, "F:/bmp_leveling.bin", tool_menu.TERN(AUTO_BED_LEVELING_BILINEAR, autoleveling, leveling), INTERVAL_V, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_LEVELING); + lv_big_button_create(scr, "F:/bmp_filamentchange.bin", tool_menu.filament, BTN_X_PIXEL+INTERVAL_V*2,BTN_Y_PIXEL+INTERVAL_H+titleHeight, event_handler,ID_T_FILAMENT); + lv_big_button_create(scr, "F:/bmp_more.bin", tool_menu.more, BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_MORE); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_T_RETURN); +} + +void lv_clear_tool() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.h new file mode 100644 index 0000000..2191adc --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_tool.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_tool(void); +extern void lv_clear_tool(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.cpp new file mode 100644 index 0000000..f997f29 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.cpp @@ -0,0 +1,117 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if BOTH(HAS_TFT_LVGL_UI, TOUCH_SCREEN_CALIBRATION) + +#include "draw_ui.h" +#include "draw_touch_calibration.h" +#include <lv_conf.h> + +#include "../../../../inc/MarlinConfig.h" +#include "../../../tft_io/touch_calibration.h" +#include "SPI_TFT.h" + +static lv_obj_t *scr; +static lv_obj_t *status_label; + +static void event_handler(lv_obj_t *obj, lv_event_t event); + +enum { + ID_TC_RETURN = 1 +}; + +static void drawCross(uint16_t x, uint16_t y, uint16_t color) { + SPI_TFT.tftio.set_window(x - 15, y, x + 15, y); + SPI_TFT.tftio.WriteMultiple(color, 31); + SPI_TFT.tftio.set_window(x, y - 15, x, y + 15); + SPI_TFT.tftio.WriteMultiple(color, 31); +} + +void lv_update_touch_calibration_screen() { + uint16_t x, y; + + calibrationState calibration_stage = touch_calibration.get_calibration_state(); + if (calibration_stage == CALIBRATION_NONE) { + // start and clear screen + calibration_stage = touch_calibration.calibration_start(); + } + else { + // clear last cross + x = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].x; + y = touch_calibration.calibration_points[_MIN(calibration_stage - 1, CALIBRATION_BOTTOM_RIGHT)].y; + drawCross(x, y, LV_COLOR_BACKGROUND.full); + } + + const char *str = nullptr; + if (calibration_stage < CALIBRATION_SUCCESS) { + // handle current state + switch (calibration_stage) { + case CALIBRATION_TOP_LEFT: str = GET_TEXT(MSG_TOP_LEFT); break; + case CALIBRATION_BOTTOM_LEFT: str = GET_TEXT(MSG_BOTTOM_LEFT); break; + case CALIBRATION_TOP_RIGHT: str = GET_TEXT(MSG_TOP_RIGHT); break; + case CALIBRATION_BOTTOM_RIGHT: str = GET_TEXT(MSG_BOTTOM_RIGHT); break; + default: break; + } + + x = touch_calibration.calibration_points[calibration_stage].x; + y = touch_calibration.calibration_points[calibration_stage].y; + drawCross(x, y, LV_COLOR_WHITE.full); + } + else { + // end calibration + str = calibration_stage == CALIBRATION_SUCCESS ? GET_TEXT(MSG_CALIBRATION_COMPLETED) : GET_TEXT(MSG_CALIBRATION_FAILED); + touch_calibration.calibration_end(); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_TC_RETURN); + } + + // draw current message + lv_label_set_text(status_label, str); + lv_obj_align(status_label, nullptr, LV_ALIGN_CENTER, 0, 0); +} + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_TC_RETURN: + lv_clear_touch_calibration_screen(); + lv_draw_return_ui(); + break; + } +} + +void lv_draw_touch_calibration_screen() { + scr = lv_screen_create(TOUCH_CALIBRATION_UI, ""); + + status_label = lv_label_create(scr, ""); + lv_obj_align(status_label, nullptr, LV_ALIGN_CENTER, 0, 0); + + lv_refr_now(lv_refr_get_disp_refreshing()); + + lv_update_touch_calibration_screen(); +} + +void lv_clear_touch_calibration_screen() { + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI && TOUCH_SCREEN_CALIBRATION diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.h new file mode 100644 index 0000000..63749a2 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_touch_calibration.h @@ -0,0 +1,34 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_touch_calibration_screen(); +extern void lv_clear_touch_calibration_screen(); +extern void lv_update_touch_calibration_screen(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.cpp new file mode 100644 index 0000000..55d8a1b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.cpp @@ -0,0 +1,101 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "../../../../MarlinCore.h" +#include "../../../../gcode/queue.h" +#include "../../../../module/probe.h" + +#include "draw_ui.h" + +extern lv_group_t * g; +static lv_obj_t * scr, * zOffsetText; + +enum { + ID_TM_INIT = 1, + ID_TM_ZOFFSETPOS, + ID_TM_ZOFFSETNEG, + ID_TM_SAVE, + ID_TM_TEST, + ID_TM_RETURN + }; + +static void event_handler(lv_obj_t * obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_TM_INIT: + queue.inject_P(PSTR("M851 Z0\nG28\nG1 Z0 F200\nM211 S0")); + break; + case ID_TM_ZOFFSETPOS: + queue.inject_P(PSTR("M290 Z0.1")); + break; + case ID_TM_ZOFFSETNEG: + queue.inject_P(PSTR("M290 Z-0.1")); + break; + case ID_TM_SAVE: + queue.inject_P(PSTR("M211 S1\nM500\nG28 X Y")); + break; + case ID_TM_TEST: + queue.inject_P(PSTR("G28\nG1 Z0")); + break; + case ID_TM_RETURN: + lv_clear_touchmi_settings(); + lv_draw_return_ui(); + break; + + } +} + +void lv_draw_touchmi_settings(void) { + scr = lv_screen_create(TOUCHMI_UI, machine_menu.LevelingTouchmiConf); + lv_big_button_create(scr, "F:/bmp_speed0.bin", machine_menu.TouchmiInit, INTERVAL_V, titleHeight, event_handler, ID_TM_INIT); + lv_big_button_create(scr, "F:/bmp_zAdd.bin", machine_menu.TouchmiOffsetpos, BTN_X_PIXEL + INTERVAL_V * 2, titleHeight, event_handler, ID_TM_ZOFFSETPOS); + lv_big_button_create(scr, "F:/bmp_zDec.bin", machine_menu.TouchmiOffsetneg, BTN_X_PIXEL + INTERVAL_V * 2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_TM_ZOFFSETNEG); + lv_big_button_create(scr, "F:/bmp_set.bin", machine_menu.TouchmiSave, BTN_X_PIXEL * 2 + INTERVAL_V * 3, titleHeight, event_handler, ID_TM_SAVE); + lv_big_button_create(scr, "F:/bmp_in.bin", machine_menu.TouchmiTest, BTN_X_PIXEL * 3 + INTERVAL_V * 4,titleHeight, event_handler, ID_TM_TEST); + lv_big_button_create(scr, "F:/bmp_return.bin", common_menu.text_back, BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_TM_RETURN); + + + zOffsetText = lv_label_create(scr, 290, TITLE_YPOS, nullptr); + disp_z_offset_value_TM(); +} + +void disp_z_offset_value_TM() { + char buf[20]; + #if HAS_BED_PROBE + char str_1[16]; + #endif + sprintf_P(buf, PSTR("offset Z: %s mm"), TERN(HAS_BED_PROBE, dtostrf(probe.offset.z, 1, 2, str_1), "0")); + lv_label_set_text(zOffsetText, buf); +} + + +void lv_clear_touchmi_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.h new file mode 100644 index 0000000..cea28df --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_touchmi_settings.h @@ -0,0 +1,35 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus +extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_touchmi_settings(void); +extern void lv_clear_touchmi_settings(); +extern void disp_z_offset_value_TM(); + +//extern void disp_temp_ready_print(); +#ifdef __cplusplus +} /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp new file mode 100644 index 0000000..8fc399e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.cpp @@ -0,0 +1,1510 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "SPI_TFT.h" + +#include "tft_lvgl_configuration.h" + +#include "pic_manager.h" + +#include "draw_ui.h" +#include "mks_hardware_test.h" + +#include <SPI.h> + +#include "../../../../MarlinCore.h" // for marlin_state +#include "../../../../sd/cardreader.h" +#include "../../../../module/motion.h" +#include "../../../../module/planner.h" +#include "../../../../inc/MarlinConfig.h" + +#if ENABLED(POWER_LOSS_RECOVERY) + #include "../../../../feature/powerloss.h" +#endif + +#if ENABLED(PARK_HEAD_ON_PAUSE) + #include "../../../../feature/pause.h" +#endif + +#if ENABLED(TOUCH_SCREEN_CALIBRATION) + #include "draw_touch_calibration.h" +#endif + +CFG_ITMES gCfgItems; +UI_CFG uiCfg; +DISP_STATE_STACK disp_state_stack; +DISP_STATE disp_state = MAIN_UI; +DISP_STATE last_disp_state; +PRINT_TIME print_time; +num_key_value_state value; +keyboard_value_state keyboard_value; + +uint32_t To_pre_view; +bool gcode_preview_over, flash_preview_begin, default_preview_flg; +uint32_t size = 809; +uint16_t row; +bool temps_update_flag; +uint8_t printing_rate_update_flag; + +extern bool once_flag; +extern uint8_t sel_id; +extern lv_group_t *g; + +extern uint8_t bmp_public_buf[14 * 1024]; +extern uint8_t public_buf[513]; + +extern void LCD_IO_WriteData(uint16_t RegValue); + +static const char custom_gcode_command[][100] = { + "G28\nG29\nM500", + "G28", + "G28", + "G28", + "G28" +}; + +lv_point_t line_points[4][2] = { + {{PARA_UI_POS_X, PARA_UI_POS_Y + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y + PARA_UI_SIZE_Y}}, + {{PARA_UI_POS_X, PARA_UI_POS_Y*2 + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y*2 + PARA_UI_SIZE_Y}}, + {{PARA_UI_POS_X, PARA_UI_POS_Y*3 + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y*3 + PARA_UI_SIZE_Y}}, + {{PARA_UI_POS_X, PARA_UI_POS_Y*4 + PARA_UI_SIZE_Y}, {TFT_WIDTH, PARA_UI_POS_Y*4 + PARA_UI_SIZE_Y}} +}; +void gCfgItems_init() { + gCfgItems.multiple_language = MULTI_LANGUAGE_ENABLE; + #if 1 // LCD_LANGUAGE == en + gCfgItems.language = LANG_ENGLISH; + #elif LCD_LANGUAGE == zh_CN + gCfgItems.language = LANG_SIMPLE_CHINESE; + #elif LCD_LANGUAGE == zh_TW + gCfgItems.language = LANG_COMPLEX_CHINESE; + #elif LCD_LANGUAGE == jp_kana + gCfgItems.language = LANG_JAPAN; + #elif LCD_LANGUAGE == de + gCfgItems.language = LANG_GERMAN; + #elif LCD_LANGUAGE == fr + gCfgItems.language = LANG_FRENCH; + #elif LCD_LANGUAGE == ru + gCfgItems.language = LANG_RUSSIAN; + #elif LCD_LANGUAGE == ko_KR + gCfgItems.language = LANG_KOREAN; + #elif LCD_LANGUAGE == tr + gCfgItems.language = LANG_TURKISH; + #elif LCD_LANGUAGE == es + gCfgItems.language = LANG_SPANISH; + #elif LCD_LANGUAGE == el + gCfgItems.language = LANG_GREEK; + #elif LCD_LANGUAGE == it + gCfgItems.language = LANG_ITALY; + #elif LCD_LANGUAGE == pt + gCfgItems.language = LANG_PORTUGUESE; + #endif + gCfgItems.leveling_mode = 0; + gCfgItems.from_flash_pic = false; + gCfgItems.curFilesize = 0; + gCfgItems.finish_power_off = false; + gCfgItems.pause_reprint = false; + gCfgItems.pausePosX = -1; + gCfgItems.pausePosY = -1; + gCfgItems.pausePosZ = 5; + gCfgItems.levelingPos[0][0] = X_MIN_POS + 30; + gCfgItems.levelingPos[0][1] = Y_MIN_POS + 30; + gCfgItems.levelingPos[1][0] = X_MAX_POS - 30; + gCfgItems.levelingPos[1][1] = Y_MIN_POS + 30; + gCfgItems.levelingPos[2][0] = X_MAX_POS - 30; + gCfgItems.levelingPos[2][1] = Y_MAX_POS - 30; + gCfgItems.levelingPos[3][0] = X_MIN_POS + 30; + gCfgItems.levelingPos[3][1] = Y_MAX_POS - 30; + gCfgItems.levelingPos[4][0] = X_BED_SIZE / 2; + gCfgItems.levelingPos[4][1] = Y_BED_SIZE / 2; + gCfgItems.cloud_enable = false; + gCfgItems.wifi_mode_sel = STA_MODEL; + gCfgItems.fileSysType = FILE_SYS_SD; + gCfgItems.wifi_type = ESP_WIFI; + gCfgItems.filamentchange_load_length = 200; + gCfgItems.filamentchange_load_speed = 1000; + gCfgItems.filamentchange_unload_length = 200; + gCfgItems.filamentchange_unload_speed = 1000; + gCfgItems.filament_limit_temper = 200; + + gCfgItems.encoder_enable = true; + + W25QXX.SPI_FLASH_BufferRead((uint8_t *)&gCfgItems.spi_flash_flag, VAR_INF_ADDR, sizeof(gCfgItems.spi_flash_flag)); + if (gCfgItems.spi_flash_flag == FLASH_INF_VALID_FLAG) { + W25QXX.SPI_FLASH_BufferRead((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems)); + } + else { + gCfgItems.spi_flash_flag = FLASH_INF_VALID_FLAG; + W25QXX.SPI_FLASH_SectorErase(VAR_INF_ADDR); + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems)); + //init gcode command + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[0], AUTO_LEVELING_COMMAND_ADDR, 100); + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[1], OTHERS_COMMAND_ADDR_1, 100); + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[2], OTHERS_COMMAND_ADDR_2, 100); + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[3], OTHERS_COMMAND_ADDR_3, 100); + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&custom_gcode_command[4], OTHERS_COMMAND_ADDR_4, 100); + } + + const byte rot = (TFT_ROTATION & TFT_ROTATE_180) ? 0xEE : 0x00; + if (gCfgItems.disp_rotation_180 != rot) { + gCfgItems.disp_rotation_180 = rot; + update_spi_flash(); + } + + uiCfg.F[0] = 'N'; + uiCfg.F[1] = 'A'; + uiCfg.F[2] = 'N'; + uiCfg.F[3] = 'O'; + W25QXX.SPI_FLASH_BlockErase(REFLSHE_FLGA_ADD + 32 - 64*1024); + W25QXX.SPI_FLASH_BufferWrite(uiCfg.F,REFLSHE_FLGA_ADD,4); +} + +void ui_cfg_init() { + uiCfg.curTempType = 0; + uiCfg.curSprayerChoose = 0; + uiCfg.stepHeat = 10; + uiCfg.leveling_first_time = 0; + uiCfg.para_ui_page = 0; + uiCfg.extruStep = 5; + uiCfg.extruSpeed = 10; + uiCfg.move_dist = 1; + uiCfg.moveSpeed = 3000; + uiCfg.stepPrintSpeed = 10; + uiCfg.command_send = 0; + uiCfg.dialogType = 0; + uiCfg.filament_heat_completed_load = 0; + uiCfg.filament_rate = 0; + uiCfg.filament_loading_completed = 0; + uiCfg.filament_unloading_completed = 0; + uiCfg.filament_loading_time_flg = 0; + uiCfg.filament_loading_time_cnt = 0; + uiCfg.filament_unloading_time_flg = 0; + uiCfg.filament_unloading_time_cnt = 0; + + #if ENABLED(MKS_WIFI_MODULE) + memset(&wifiPara, 0, sizeof(wifiPara)); + memset(&ipPara, 0, sizeof(ipPara)); + strcpy(wifiPara.ap_name, WIFI_AP_NAME); + strcpy(wifiPara.keyCode, WIFI_KEY_CODE); + //client + strcpy(ipPara.ip_addr, IP_ADDR); + strcpy(ipPara.mask, IP_MASK); + strcpy(ipPara.gate, IP_GATE); + strcpy(ipPara.dns, IP_DNS); + + ipPara.dhcp_flag = IP_DHCP_FLAG; + + //AP + strcpy(ipPara.dhcpd_ip, AP_IP_ADDR); + strcpy(ipPara.dhcpd_mask, AP_IP_MASK); + strcpy(ipPara.dhcpd_gate, AP_IP_GATE); + strcpy(ipPara.dhcpd_dns, AP_IP_DNS); + strcpy(ipPara.start_ip_addr, IP_START_IP); + strcpy(ipPara.end_ip_addr, IP_END_IP); + + ipPara.dhcpd_flag = AP_IP_DHCP_FLAG; + + strcpy((char*)uiCfg.cloud_hostUrl, "baizhongyun.cn"); + uiCfg.cloud_port = 10086; + #endif + + uiCfg.filament_loading_time = (uint32_t)((gCfgItems.filamentchange_load_length * 60.0 / gCfgItems.filamentchange_load_speed) + 0.5); + uiCfg.filament_unloading_time = (uint32_t)((gCfgItems.filamentchange_unload_length * 60.0 / gCfgItems.filamentchange_unload_speed) + 0.5); +} + +void update_spi_flash() { + uint8_t command_buf[512]; + + W25QXX.init(SPI_QUARTER_SPEED); + //read back the gcode command befor erase spi flash + W25QXX.SPI_FLASH_BufferRead((uint8_t *)&command_buf, GCODE_COMMAND_ADDR, sizeof(command_buf)); + W25QXX.SPI_FLASH_SectorErase(VAR_INF_ADDR); + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems)); + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&command_buf, GCODE_COMMAND_ADDR, sizeof(command_buf)); +} + +void update_gcode_command(int addr,uint8_t *s) { + uint8_t command_buf[512]; + + W25QXX.init(SPI_QUARTER_SPEED); + //read back the gcode command befor erase spi flash + W25QXX.SPI_FLASH_BufferRead((uint8_t *)&command_buf, GCODE_COMMAND_ADDR, sizeof(command_buf)); + W25QXX.SPI_FLASH_SectorErase(VAR_INF_ADDR); + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&gCfgItems, VAR_INF_ADDR, sizeof(gCfgItems)); + switch (addr) { + case AUTO_LEVELING_COMMAND_ADDR: memcpy(&command_buf[0*100], s, 100); break; + case OTHERS_COMMAND_ADDR_1: memcpy(&command_buf[1*100], s, 100); break; + case OTHERS_COMMAND_ADDR_2: memcpy(&command_buf[2*100], s, 100); break; + case OTHERS_COMMAND_ADDR_3: memcpy(&command_buf[3*100], s, 100); break; + case OTHERS_COMMAND_ADDR_4: memcpy(&command_buf[4*100], s, 100); break; + default: break; + } + W25QXX.SPI_FLASH_BufferWrite((uint8_t *)&command_buf, GCODE_COMMAND_ADDR, sizeof(command_buf)); +} + +void get_gcode_command(int addr,uint8_t *d) { + W25QXX.init(SPI_QUARTER_SPEED); + W25QXX.SPI_FLASH_BufferRead((uint8_t *)d, addr, 100); +} + +lv_style_t tft_style_scr; +lv_style_t tft_style_label_pre; +lv_style_t tft_style_label_rel; +lv_style_t style_line; +lv_style_t style_para_value_pre; +lv_style_t style_para_value_rel; + +lv_style_t style_num_key_pre; +lv_style_t style_num_key_rel; + +lv_style_t style_num_text; +lv_style_t style_sel_text; + +lv_style_t style_para_value; +lv_style_t style_para_back; + +lv_style_t lv_bar_style_indic; + +lv_style_t style_btn_pr; +lv_style_t style_btn_rel; + +void tft_style_init() { + lv_style_copy(&tft_style_scr, &lv_style_scr); + tft_style_scr.body.main_color = LV_COLOR_BACKGROUND; + tft_style_scr.body.grad_color = LV_COLOR_BACKGROUND; + tft_style_scr.text.color = LV_COLOR_TEXT; + tft_style_scr.text.sel_color = LV_COLOR_TEXT; + tft_style_scr.line.width = 0; + tft_style_scr.text.letter_space = 0; + tft_style_scr.text.line_space = 0; + + lv_style_copy(&tft_style_label_pre, &lv_style_scr); + lv_style_copy(&tft_style_label_rel, &lv_style_scr); + tft_style_label_pre.body.main_color = LV_COLOR_BACKGROUND; + tft_style_label_pre.body.grad_color = LV_COLOR_BACKGROUND; + tft_style_label_pre.text.color = LV_COLOR_TEXT; + tft_style_label_pre.text.sel_color = LV_COLOR_TEXT; + tft_style_label_rel.body.main_color = LV_COLOR_BACKGROUND; + tft_style_label_rel.body.grad_color = LV_COLOR_BACKGROUND; + tft_style_label_rel.text.color = LV_COLOR_TEXT; + tft_style_label_rel.text.sel_color = LV_COLOR_TEXT; + tft_style_label_pre.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT); + tft_style_label_rel.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT); + tft_style_label_pre.line.width = 0; + tft_style_label_rel.line.width = 0; + tft_style_label_pre.text.letter_space = 0; + tft_style_label_rel.text.letter_space = 0; + tft_style_label_pre.text.line_space = 0; + tft_style_label_rel.text.line_space = 0; + + lv_style_copy(&style_para_value_pre, &lv_style_scr); + lv_style_copy(&style_para_value_rel, &lv_style_scr); + style_para_value_pre.body.main_color = LV_COLOR_BACKGROUND; + style_para_value_pre.body.grad_color = LV_COLOR_BACKGROUND; + style_para_value_pre.text.color = LV_COLOR_TEXT; + style_para_value_pre.text.sel_color = LV_COLOR_TEXT; + style_para_value_rel.body.main_color = LV_COLOR_BACKGROUND; + style_para_value_rel.body.grad_color = LV_COLOR_BACKGROUND; + style_para_value_rel.text.color = LV_COLOR_BLACK; + style_para_value_rel.text.sel_color = LV_COLOR_BLACK; + style_para_value_pre.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT); + style_para_value_rel.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT); + style_para_value_pre.line.width = 0; + style_para_value_rel.line.width = 0; + style_para_value_pre.text.letter_space = 0; + style_para_value_rel.text.letter_space = 0; + style_para_value_pre.text.line_space = 0; + style_para_value_rel.text.line_space = 0; + + lv_style_copy(&style_num_key_pre, &lv_style_scr); + lv_style_copy(&style_num_key_rel, &lv_style_scr); + style_num_key_pre.body.main_color = LV_COLOR_KEY_BACKGROUND; + style_num_key_pre.body.grad_color = LV_COLOR_KEY_BACKGROUND; + style_num_key_pre.text.color = LV_COLOR_TEXT; + style_num_key_pre.text.sel_color = LV_COLOR_TEXT; + style_num_key_rel.body.main_color = LV_COLOR_KEY_BACKGROUND; + style_num_key_rel.body.grad_color = LV_COLOR_KEY_BACKGROUND; + style_num_key_rel.text.color = LV_COLOR_TEXT; + style_num_key_rel.text.sel_color = LV_COLOR_TEXT; + #if HAS_SPI_FLASH_FONT + style_num_key_pre.text.font = &gb2312_puhui32; + style_num_key_rel.text.font = &gb2312_puhui32; + #else + style_num_key_pre.text.font = LV_FONT_DEFAULT; + style_num_key_rel.text.font = LV_FONT_DEFAULT; + #endif + style_num_key_pre.line.width = 0; + style_num_key_rel.line.width = 0; + style_num_key_pre.text.letter_space = 0; + style_num_key_rel.text.letter_space = 0; + style_num_key_pre.text.line_space = 0; + style_num_key_rel.text.line_space = 0; + + lv_style_copy(&style_num_text, &lv_style_scr); + style_num_text.body.main_color = LV_COLOR_WHITE; + style_num_text.body.grad_color = LV_COLOR_WHITE; + style_num_text.text.color = LV_COLOR_BLACK; + style_num_text.text.sel_color = LV_COLOR_BLACK; + style_num_text.text.font = TERN(HAS_SPI_FLASH_FONT, &gb2312_puhui32, LV_FONT_DEFAULT); + style_num_text.line.width = 0; + style_num_text.text.letter_space = 0; + style_num_text.text.line_space = 0; + + lv_style_copy(&style_sel_text, &lv_style_scr); + style_sel_text.body.main_color = LV_COLOR_BACKGROUND; + style_sel_text.body.grad_color = LV_COLOR_BACKGROUND; + style_sel_text.text.color = LV_COLOR_YELLOW; + style_sel_text.text.sel_color = LV_COLOR_YELLOW; + style_sel_text.text.font = &gb2312_puhui32; + style_sel_text.line.width = 0; + style_sel_text.text.letter_space = 0; + style_sel_text.text.line_space = 0; + lv_style_copy(&style_line, &lv_style_plain); + style_line.line.color = LV_COLOR_MAKE(0x49, 0x54, 0xFF); + style_line.line.width = 1; + style_line.line.rounded = 1; + + lv_style_copy(&style_para_value, &lv_style_plain); + style_para_value.body.border.color = LV_COLOR_BACKGROUND; + style_para_value.body.border.width = 1; + style_para_value.body.main_color = LV_COLOR_WHITE; + style_para_value.body.grad_color = LV_COLOR_WHITE; + style_para_value.body.shadow.width = 0; + style_para_value.body.radius = 3; + style_para_value.text.color = LV_COLOR_BLACK; + style_para_value.text.font = &TERN(HAS_SPI_FLASH_FONT, gb2312_puhui32, lv_font_roboto_22); + + lv_style_copy(&style_para_back, &lv_style_plain); + style_para_back.body.border.color = LV_COLOR_BACKGROUND; + style_para_back.body.border.width = 1; + style_para_back.body.main_color = TFT_LV_PARA_BACK_BODY_COLOR; + style_para_back.body.grad_color = TFT_LV_PARA_BACK_BODY_COLOR; + style_para_back.body.shadow.width = 0; + style_para_back.body.radius = 3; + style_para_back.text.color = LV_COLOR_WHITE; + style_para_back.text.font = &TERN(HAS_SPI_FLASH_FONT, gb2312_puhui32, lv_font_roboto_22); + + lv_style_copy(&style_btn_rel, &lv_style_plain); + style_btn_rel.body.border.color = lv_color_hex3(0x269); + style_btn_rel.body.border.width = 1; + style_btn_rel.body.main_color = lv_color_hex3(0xADF); + style_btn_rel.body.grad_color = lv_color_hex3(0x46B); + style_btn_rel.body.shadow.width = 4; + style_btn_rel.body.shadow.type = LV_SHADOW_BOTTOM; + style_btn_rel.body.radius = LV_RADIUS_CIRCLE; + style_btn_rel.text.color = lv_color_hex3(0xDEF); + style_btn_rel.text.font = &TERN(HAS_SPI_FLASH_FONT, gb2312_puhui32, lv_font_roboto_22); + + lv_style_copy(&style_btn_pr, &style_btn_rel); + style_btn_pr.body.border.color = lv_color_hex3(0x46B); + style_btn_pr.body.main_color = lv_color_hex3(0x8BD); + style_btn_pr.body.grad_color = lv_color_hex3(0x24A); + style_btn_pr.body.shadow.width = 2; + style_btn_pr.text.color = lv_color_hex3(0xBCD); + style_btn_pr.text.font = &TERN(HAS_SPI_FLASH_FONT, gb2312_puhui32, lv_font_roboto_22); + + lv_style_copy(&lv_bar_style_indic, &lv_style_pretty_color); + lv_bar_style_indic.text.color = lv_color_hex3(0xADF); + lv_bar_style_indic.image.color = lv_color_hex3(0xADF); + lv_bar_style_indic.line.color = lv_color_hex3(0xADF); + lv_bar_style_indic.body.main_color = lv_color_hex3(0xADF); + lv_bar_style_indic.body.grad_color = lv_color_hex3(0xADF); + lv_bar_style_indic.body.border.color = lv_color_hex3(0xADF); +} + +#define MAX_TITLE_LEN 28 + +char public_buf_m[100] = {0}; +char public_buf_l[30]; + +void titleText_cat(char *str, int strSize, char *addPart) { + if (str == 0 || addPart == 0) return; + if ((int)(strlen(str) + strlen(addPart)) >= strSize) return; + strcat(str, addPart); +} + +char *getDispText(int index) { + + ZERO(public_buf_l); + + switch (disp_state_stack._disp_state[index]) { + case PRINT_READY_UI: + strcpy(public_buf_l, main_menu.title); + break; + case PRINT_FILE_UI: + strcpy(public_buf_l, file_menu.title); + break; + case PRINTING_UI: + if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI + #ifndef TFT35 + || disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI + || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI + #endif + ) strcpy(public_buf_l, common_menu.print_special_title); + else strcpy(public_buf_l, printing_menu.title); + break; + case MOVE_MOTOR_UI: + strcpy(public_buf_l, move_menu.title); + break; + case OPERATE_UI: + if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI + #ifndef TFT35 + || disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI + || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI + #endif + ) strcpy(public_buf_l, common_menu.operate_special_title); + else strcpy(public_buf_l, operation_menu.title); + break; + + case PAUSE_UI: + if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI + || disp_state_stack._disp_state[disp_state_stack._disp_index] == OPERATE_UI + || disp_state_stack._disp_state[disp_state_stack._disp_index] == PAUSE_UI + ) strcpy(public_buf_l, common_menu.pause_special_title); + else strcpy(public_buf_l, pause_menu.title); + break; + + case EXTRUSION_UI: + strcpy(public_buf_l, extrude_menu.title); + break; + case CHANGE_SPEED_UI: + strcpy(public_buf_l, speed_menu.title); + break; + case FAN_UI: + strcpy(public_buf_l, fan_menu.title); + break; + case PRE_HEAT_UI: + if ((disp_state_stack._disp_state[disp_state_stack._disp_index - 1] == OPERATE_UI)) + strcpy(public_buf_l, preheat_menu.adjust_title); + else strcpy(public_buf_l, preheat_menu.title); + break; + case SET_UI: + strcpy(public_buf_l, set_menu.title); + break; + case ZERO_UI: + strcpy(public_buf_l, home_menu.title); + break; + case SPRAYER_UI: break; + case MACHINE_UI: break; + case LANGUAGE_UI: + strcpy(public_buf_l, language_menu.title); + break; + case ABOUT_UI: + strcpy(public_buf_l, about_menu.title); + break; + case LOG_UI: break; + case DISK_UI: + strcpy(public_buf_l, filesys_menu.title); + break; + case DIALOG_UI: + strcpy(public_buf_l, common_menu.dialog_confirm_title); + break; + case WIFI_UI: + strcpy(public_buf_l, wifi_menu.title); + break; + case MORE_UI: + case PRINT_MORE_UI: + strcpy(public_buf_l, more_menu.title); + break; + case FILAMENTCHANGE_UI: + strcpy(public_buf_l, filament_menu.title); + break; + case LEVELING_UI: + case MESHLEVELING_UI: + strcpy(public_buf_l, leveling_menu.title); + break; + case BIND_UI: + strcpy(public_buf_l, cloud_menu.title); + break; + case TOOL_UI: + strcpy(public_buf_l, tool_menu.title); + break; + case WIFI_LIST_UI: + #if ENABLED(MKS_WIFI_MODULE) + strcpy(public_buf_l, list_menu.title); + break; + #endif + case MACHINE_PARA_UI: + strcpy(public_buf_l, MachinePara_menu.title); + break; + case BABY_STEP_UI: + strcpy(public_buf_l, operation_menu.babystep); + break; + case EEPROM_SETTINGS_UI: + strcpy(public_buf_l, eeprom_menu.title); + break; + default: break; + } + + return public_buf_l; +} + +char *creat_title_text() { + int index = 0; + char *tmpText = 0; + char tmpCurFileStr[20]; + + ZERO(tmpCurFileStr); + + cutFileName(list_file.long_name[sel_id], 16, 16, tmpCurFileStr); + + ZERO(public_buf_m); + + while (index <= disp_state_stack._disp_index) { + tmpText = getDispText(index); + if ((*tmpText == 0) || (tmpText == 0)) { + index++; + continue; + } + + titleText_cat(public_buf_m, sizeof(public_buf_m), tmpText); + if (index < disp_state_stack._disp_index) titleText_cat(public_buf_m, sizeof(public_buf_m), (char *)">"); + + index++; + } + + if (disp_state_stack._disp_state[disp_state_stack._disp_index] == PRINTING_UI) { + titleText_cat(public_buf_m, sizeof(public_buf_m), (char *)":"); + titleText_cat(public_buf_m, sizeof(public_buf_m), tmpCurFileStr); + } + + if (strlen(public_buf_m) > MAX_TITLE_LEN) { + ZERO(public_buf_m); + tmpText = 0; + for (index = 0; index <= disp_state_stack._disp_index && (!tmpText || *tmpText == 0); index++) + tmpText = getDispText(index); + if (*tmpText != 0) { + titleText_cat(public_buf_m, sizeof(public_buf_m), tmpText); + titleText_cat(public_buf_m, sizeof(public_buf_m), (char *)">...>"); + tmpText = getDispText(disp_state_stack._disp_index); + if (*tmpText != 0) titleText_cat(public_buf_m, sizeof(public_buf_m), tmpText); + } + } + + return public_buf_m; +} + +#if HAS_GCODE_PREVIEW + + uint32_t gPicturePreviewStart = 0; + + void preview_gcode_prehandle(char *path) { + #if ENABLED(SDSUPPORT) + uint32_t pre_read_cnt = 0; + uint32_t *p1; + //char *cur_name; + + gPicturePreviewStart = 0; + //cur_name = strrchr(path, '/'); + card.openFileRead(path); + card.read(public_buf, 512); + p1 = (uint32_t *)strstr((char *)public_buf, ";simage:"); + + if (p1) { + pre_read_cnt = (uint32_t)p1 - (uint32_t)((uint32_t *)(&public_buf[0])); + + To_pre_view = pre_read_cnt; + gcode_preview_over = true; + gCfgItems.from_flash_pic = true; + update_spi_flash(); + } + else { + gcode_preview_over = false; + default_preview_flg = true; + gCfgItems.from_flash_pic = false; + update_spi_flash(); + } + card.closefile(); + #endif + } + + void gcode_preview(char *path, int xpos_pixel, int ypos_pixel) { + #if ENABLED(SDSUPPORT) + volatile uint32_t i, j; + volatile uint16_t *p_index; + //char *cur_name; + + //cur_name = strrchr(path, '/'); + card.openFileRead(path); + + if (gPicturePreviewStart <= 0) { + while (1) { + uint32_t br = card.read(public_buf, 400); + uint32_t* p1 = (uint32_t *)strstr((char *)public_buf, ";gimage:"); + if (p1) { + gPicturePreviewStart += (uint32_t)p1 - (uint32_t)((uint32_t *)(&public_buf[0])); + break; + } + else { + gPicturePreviewStart += br; + } + if (br < 400) break; + } + } + + card.setIndex(gPicturePreviewStart + size * row + 8); + SPI_TFT.setWindow(xpos_pixel, ypos_pixel + row, 200, 1); + + j = i = 0; + + while (1) { + card.read(public_buf, 400); + for (i = 0; i < 400;) { + bmp_public_buf[j] = ascii2dec_test((char*)&public_buf[i]) << 4 | ascii2dec_test((char*)&public_buf[i + 1]); + i += 2; + j++; + } + if (j >= 400) break; + } + for (i = 0; i < 400; i += 2) { + p_index = (uint16_t *)(&bmp_public_buf[i]); + if (*p_index == 0x0000) *p_index = LV_COLOR_BACKGROUND.full; + } + SPI_TFT.tftio.WriteSequence((uint16_t*)bmp_public_buf, 200); + #if HAS_BAK_VIEW_IN_FLASH + W25QXX.init(SPI_QUARTER_SPEED); + if (row < 20) W25QXX.SPI_FLASH_SectorErase(BAK_VIEW_ADDR_TFT35 + row * 4096); + W25QXX.SPI_FLASH_BufferWrite(bmp_public_buf, BAK_VIEW_ADDR_TFT35 + row * 400, 400); + #endif + row++; + if (row >= 200) { + size = 809; + row = 0; + + gcode_preview_over = false; + + card.closefile(); + //char *cur_name; + + //cur_name = strrchr(list_file.file_name[sel_id], '/'); + + //SdFile file; + //SdFile *curDir; + card.endFilePrint(); + //const char * const fname = card.diveToFile(true, curDir, cur_name); + //if (!fname) return; + //if (file.open(curDir, fname, O_READ)) { + //gCfgItems.curFilesize = file.fileSize(); + //file.close(); + //update_spi_flash(); + //} + + card.openFileRead(list_file.file_name[sel_id]); + if (card.isFileOpen()) { + gCfgItems.curFilesize = card.getFileSize(); + update_spi_flash(); + feedrate_percentage = 100; + planner.flow_percentage[0] = 100; + planner.e_factor[0] = planner.flow_percentage[0] * 0.01; + #if HAS_MULTI_EXTRUDER + planner.flow_percentage[1] = 100; + planner.e_factor[1] = planner.flow_percentage[1] * 0.01; + #endif + card.startFileprint(); + TERN_(POWER_LOSS_RECOVERY, recovery.prepare()); + once_flag = false; + } + return; + } + card.closefile(); + #endif // SDSUPPORT + } + + void draw_default_preview(int xpos_pixel, int ypos_pixel, uint8_t sel) { + int index; + int y_off = 0; + W25QXX.init(SPI_QUARTER_SPEED); + for (index = 0; index < 10; index++) { // 200*200 + #if HAS_BAK_VIEW_IN_FLASH + if (sel == 1) { + flash_view_Read(bmp_public_buf, 8000); // 20k + } + else { + default_view_Read(bmp_public_buf, DEFAULT_VIEW_MAX_SIZE / 10); // 8k + } + #else + default_view_Read(bmp_public_buf, DEFAULT_VIEW_MAX_SIZE / 10); // 8k + #endif + + SPI_TFT.setWindow(xpos_pixel, y_off * 20 + ypos_pixel, 200, 20); // 200*200 + SPI_TFT.tftio.WriteSequence((uint16_t*)(bmp_public_buf), DEFAULT_VIEW_MAX_SIZE / 20); + + y_off++; + } + W25QXX.init(SPI_QUARTER_SPEED); + } + + void disp_pre_gcode(int xpos_pixel, int ypos_pixel) { + if (gcode_preview_over) gcode_preview(list_file.file_name[sel_id], xpos_pixel, ypos_pixel); + #if HAS_BAK_VIEW_IN_FLASH + if (flash_preview_begin) { + flash_preview_begin = false; + draw_default_preview(xpos_pixel, ypos_pixel, 1); + } + #endif + #if HAS_GCODE_DEFAULT_VIEW_IN_FLASH + if (default_preview_flg) { + draw_default_preview(xpos_pixel, ypos_pixel, 0); + default_preview_flg = false; + } + #endif + } +#endif // HAS_GCODE_PREVIEW + +void print_time_run() { + static uint8_t lastSec = 0; + + if (print_time.seconds >= 60) { + print_time.seconds = 0; + print_time.minutes++; + if (print_time.minutes >= 60) { + print_time.minutes = 0; + print_time.hours++; + } + } + if (disp_state == PRINTING_UI) { + if (lastSec != print_time.seconds) disp_print_time(); + lastSec = print_time.seconds; + } +} + +void GUI_RefreshPage() { + if ((systick_uptime_millis % 1000) == 0) temps_update_flag = true; + if ((systick_uptime_millis % 3000) == 0) printing_rate_update_flag = true; + + switch (disp_state) { + case MAIN_UI: + break; + case EXTRUSION_UI: + if (temps_update_flag) { + temps_update_flag = false; + disp_hotend_temp(); + } + break; + case PRE_HEAT_UI: + if (temps_update_flag) { + temps_update_flag = false; + disp_desire_temp(); + } + break; + case PRINT_READY_UI: + break; + + case PRINT_FILE_UI: break; + + case PRINTING_UI: + if (temps_update_flag) { + temps_update_flag = false; + disp_ext_temp(); + disp_bed_temp(); + disp_fan_speed(); + disp_print_time(); + disp_fan_Zpos(); + } + if (printing_rate_update_flag || marlin_state == MF_SD_COMPLETE) { + printing_rate_update_flag = false; + if (!gcode_preview_over) setProBarRate(); + } + break; + + case OPERATE_UI: + break; + + case PAUSE_UI: + break; + + case FAN_UI: + if (temps_update_flag) { + temps_update_flag = false; + disp_fan_value(); + } + break; + + case MOVE_MOTOR_UI: + break; + + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_UI: + if (temps_update_flag) { + disp_wifi_state(); + temps_update_flag = false; + } + break; + + case BIND_UI: + refresh_bind_ui(); + break; + #endif + case FILAMENTCHANGE_UI: + if (temps_update_flag) { + temps_update_flag = false; + disp_filament_temp(); + } + break; + case DIALOG_UI: + filament_dialog_handle(); + TERN_(MKS_WIFI_MODULE, wifi_scan_handle()); + break; + case MESHLEVELING_UI: + break; + case HARDWARE_TEST_UI: + break; + case WIFI_LIST_UI: + #if ENABLED(MKS_WIFI_MODULE) + if (printing_rate_update_flag) { + disp_wifi_list(); + printing_rate_update_flag = false; + } + #endif + break; + case KEY_BOARD_UI: + break; + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_TIPS_UI: + switch (wifi_tips_type) { + case TIPS_TYPE_JOINING: + if (wifi_link_state == WIFI_CONNECTED && strcmp((const char *)wifi_list.wifiConnectedName,(const char *)wifi_list.wifiName[wifi_list.nameIndex]) == 0) { + tips_disp.timer = TIPS_TIMER_STOP; + tips_disp.timer_count = 0; + + lv_clear_wifi_tips(); + wifi_tips_type = TIPS_TYPE_WIFI_CONECTED; + lv_draw_wifi_tips(); + + } + if (tips_disp.timer_count >= 30 * 1000) { + tips_disp.timer = TIPS_TIMER_STOP; + tips_disp.timer_count = 0; + lv_clear_wifi_tips(); + wifi_tips_type = TIPS_TYPE_TAILED_JOIN; + lv_draw_wifi_tips(); + } + break; + case TIPS_TYPE_TAILED_JOIN: + if (tips_disp.timer_count >= 3 * 1000) { + tips_disp.timer = TIPS_TIMER_STOP; + tips_disp.timer_count = 0; + + last_disp_state = WIFI_TIPS_UI; + lv_clear_wifi_tips(); + lv_draw_wifi_list(); + } + break; + case TIPS_TYPE_WIFI_CONECTED: + if (tips_disp.timer_count >= 3 * 1000) { + tips_disp.timer = TIPS_TIMER_STOP; + tips_disp.timer_count = 0; + + last_disp_state = WIFI_TIPS_UI; + lv_clear_wifi_tips(); + lv_draw_wifi(); + } + break; + default: break; + } + break; + #endif + + case BABY_STEP_UI: + if (temps_update_flag) { + temps_update_flag = false; + disp_z_offset_value(); + } + break; + + #if ENABLED(BLTOUCH) + case BLTOUCH_UI: + if (temps_update_flag) { + temps_update_flag = false; + disp_bltouch_z_offset_value(); + } + break; + #endif + + #if ENABLED(TOUCH_MI_PROBE) + case TOUCHMI_UI: + if (temps_update_flag) { + temps_update_flag = false; + disp_z_offset_value_TM(); + } + break; + #endif + default: break; + } + + print_time_run(); +} + +void lv_clear_cur_ui() { + last_disp_state = disp_state_stack._disp_state[disp_state_stack._disp_index]; + + switch (disp_state_stack._disp_state[disp_state_stack._disp_index]) { + case PRINT_READY_UI: + lv_clear_ready_print(); break; + case PRINT_FILE_UI: lv_clear_print_file(); break; + case PRINTING_UI: lv_clear_printing(); break; + case MOVE_MOTOR_UI: lv_clear_move_motor(); break; + case OPERATE_UI: lv_clear_operation(); break; + case PAUSE_UI: break; + case EXTRUSION_UI: lv_clear_extrusion(); break; + case PRE_HEAT_UI: lv_clear_preHeat(); break; + case CHANGE_SPEED_UI: lv_clear_change_speed(); break; + case FAN_UI: lv_clear_fan(); break; + case SET_UI: lv_clear_set(); break; + case ZERO_UI: lv_clear_home(); break; + case SPRAYER_UI: break; + case MACHINE_UI: break; + case LANGUAGE_UI: lv_clear_language(); break; + case ABOUT_UI: lv_clear_about(); break; + case LOG_UI: break; + case DISK_UI: break; + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_UI: lv_clear_wifi(); break; + #endif + case MORE_UI: lv_clear_more(); break; + case FILETRANSFER_UI: break; + case DIALOG_UI: lv_clear_dialog(); break; + case FILETRANSFERSTATE_UI: break; + case PRINT_MORE_UI: break; + case FILAMENTCHANGE_UI: lv_clear_filament_change(); break; + case LEVELING_UI: lv_clear_manualLevel(); break; + #if ENABLED(MKS_WIFI_MODULE) + case BIND_UI: lv_clear_cloud_bind(); break; + #endif + #if HAS_BED_PROBE + case NOZZLE_PROBE_OFFSET_UI: lv_clear_auto_level_offset_settings(); break; + #endif + case TOOL_UI: lv_clear_tool(); break; + case MESHLEVELING_UI: break; + case HARDWARE_TEST_UI: break; + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_LIST_UI: lv_clear_wifi_list(); break; + #endif + case KEY_BOARD_UI: lv_clear_keyboard(); break; + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_TIPS_UI: lv_clear_wifi_tips(); break; + #endif + case MACHINE_PARA_UI: lv_clear_machine_para(); break; + case MACHINE_SETTINGS_UI: lv_clear_machine_settings(); break; + case TEMPERATURE_SETTINGS_UI: break; + case MOTOR_SETTINGS_UI: lv_clear_motor_settings(); break; + case MACHINETYPE_UI: break; + case STROKE_UI: break; + case HOME_DIR_UI: break; + case ENDSTOP_TYPE_UI: break; + case FILAMENT_SETTINGS_UI: break; + case LEVELING_SETTIGNS_UI: break; + case LEVELING_PARA_UI: lv_clear_level_settings(); break; + case DELTA_LEVELING_PARA_UI: break; + case MANUAL_LEVELING_POSIGION_UI: lv_clear_manual_level_pos_settings(); break; + case MAXFEEDRATE_UI: lv_clear_max_feedrate_settings(); break; + case STEPS_UI: lv_clear_step_settings(); break; + case ACCELERATION_UI: lv_clear_acceleration_settings(); break; + case JERK_UI: TERN_(HAS_CLASSIC_JERK, lv_clear_jerk_settings()); break; + case MOTORDIR_UI: break; + case HOMESPEED_UI: break; + case NOZZLE_CONFIG_UI: break; + case HOTBED_CONFIG_UI: break; + case ADVANCED_UI: lv_clear_advance_settings(); break; + case DOUBLE_Z_UI: break; + case ENABLE_INVERT_UI: break; + case NUMBER_KEY_UI: lv_clear_number_key(); break; + case BABY_STEP_UI: lv_clear_baby_stepping(); break; + #if ENABLED(BLTOUCH) + case BLTOUCH_UI: lv_clear_bltouch_settings(); break; + #endif + #if ENABLED(TOUCH_MI_PROBE) + case TOUCHMI_UI: lv_clear_touchmi_settings(); break; + #endif + case PAUSE_POS_UI: lv_clear_pause_position(); break; + #if HAS_TRINAMIC_CONFIG + case TMC_CURRENT_UI: lv_clear_tmc_current_settings(); break; + #endif + case EEPROM_SETTINGS_UI: lv_clear_eeprom_settings(); break; + #if HAS_STEALTHCHOP + case TMC_MODE_UI: lv_clear_tmc_step_mode_settings(); break; + #endif + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_SETTINGS_UI: lv_clear_wifi_settings(); break; + #endif + #if USE_SENSORLESS + case HOMING_SENSITIVITY_UI: lv_clear_homing_sensitivity_settings(); break; + #endif + #if HAS_ROTARY_ENCODER + case ENCODER_SETTINGS_UI: lv_clear_encoder_settings(); break; + #endif + #if ENABLED(TOUCH_SCREEN_CALIBRATION) + case TOUCH_CALIBRATION_UI: lv_clear_touch_calibration_screen(); break; + #endif + default: break; + } +} + +void lv_draw_return_ui() { + if (disp_state_stack._disp_index > 0) { + disp_state_stack._disp_index--; + + switch (disp_state_stack._disp_state[disp_state_stack._disp_index]) { + case PRINT_READY_UI: lv_draw_ready_print(); break; + case PRINT_FILE_UI: lv_draw_print_file(); break; + + case PRINTING_UI: if (gCfgItems.from_flash_pic) + flash_preview_begin = true; + else + default_preview_flg = true; + lv_draw_printing(); + break; + + case MOVE_MOTOR_UI: lv_draw_move_motor(); break; + case OPERATE_UI: lv_draw_operation(); break; + case PAUSE_UI: break; + case EXTRUSION_UI: lv_draw_extrusion(); break; + case PRE_HEAT_UI: lv_draw_preHeat(); break; + case CHANGE_SPEED_UI: lv_draw_change_speed(); break; + case FAN_UI: lv_draw_fan(); break; + case SET_UI: lv_draw_set(); break; + case ZERO_UI: lv_draw_home(); break; + case SPRAYER_UI: break; + case MACHINE_UI: break; + case LANGUAGE_UI: lv_draw_language(); break; + case ABOUT_UI: lv_draw_about(); break; + + case CALIBRATE_UI: break; + case DISK_UI: break; + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_UI: lv_draw_wifi(); break; + #endif + case MORE_UI: break; + case PRINT_MORE_UI: lv_draw_more(); break; + case FILAMENTCHANGE_UI: lv_draw_filament_change(); break; + case LEVELING_UI: lv_draw_manualLevel(); break; + #if ENABLED(MKS_WIFI_MODULE) + case BIND_UI: lv_draw_cloud_bind(); break; + #endif + #if HAS_BED_PROBE + case NOZZLE_PROBE_OFFSET_UI: lv_draw_auto_level_offset_settings(); break; + #endif + case TOOL_UI: lv_draw_tool(); break; + case MESHLEVELING_UI: break; + case HARDWARE_TEST_UI: break; + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_LIST_UI: lv_draw_wifi_list(); break; + #endif + case KEY_BOARD_UI: lv_draw_keyboard(); break; + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_TIPS_UI: lv_draw_wifi_tips(); break; + #endif + case MACHINE_PARA_UI: lv_draw_machine_para(); break; + case MACHINE_SETTINGS_UI: lv_draw_machine_settings(); break; + case TEMPERATURE_SETTINGS_UI: break; + case MOTOR_SETTINGS_UI: lv_draw_motor_settings(); break; + case MACHINETYPE_UI: break; + case STROKE_UI: break; + case HOME_DIR_UI: break; + case ENDSTOP_TYPE_UI: break; + case FILAMENT_SETTINGS_UI: lv_draw_filament_settings(); break; + case LEVELING_SETTIGNS_UI: break; + case LEVELING_PARA_UI: lv_draw_level_settings(); break; + case DELTA_LEVELING_PARA_UI: break; + case MANUAL_LEVELING_POSIGION_UI: lv_draw_manual_level_pos_settings(); break; + case MAXFEEDRATE_UI: lv_draw_max_feedrate_settings(); break; + case STEPS_UI: lv_draw_step_settings(); break; + case ACCELERATION_UI: lv_draw_acceleration_settings(); break; + #if HAS_CLASSIC_JERK + case JERK_UI: lv_draw_jerk_settings(); break; + #endif + case MOTORDIR_UI: break; + case HOMESPEED_UI: break; + case NOZZLE_CONFIG_UI: break; + case HOTBED_CONFIG_UI: break; + case ADVANCED_UI: lv_draw_advance_settings(); break; + case DOUBLE_Z_UI: break; + case ENABLE_INVERT_UI: break; + case NUMBER_KEY_UI: lv_draw_number_key(); break; + case DIALOG_UI: break; + case BABY_STEP_UI: lv_draw_baby_stepping(); break; + case PAUSE_POS_UI: lv_draw_pause_position(); break; + #if HAS_TRINAMIC_CONFIG + case TMC_CURRENT_UI: lv_draw_tmc_current_settings(); break; + #endif + case EEPROM_SETTINGS_UI: lv_draw_eeprom_settings(); break; + #if HAS_STEALTHCHOP + case TMC_MODE_UI: lv_draw_tmc_step_mode_settings(); break; + #endif + #if ENABLED(MKS_WIFI_MODULE) + case WIFI_SETTINGS_UI: lv_draw_wifi_settings(); break; + #endif + #if USE_SENSORLESS + case HOMING_SENSITIVITY_UI: lv_draw_homing_sensitivity_settings(); break; + #endif + #if HAS_ROTARY_ENCODER + case ENCODER_SETTINGS_UI: lv_draw_encoder_settings(); break; + #endif + case TOUCHMI_UI: lv_draw_touchmi_settings(); break; + default: break; + } + } +} + +// Set the same image for both Released and Pressed +void lv_imgbtn_set_src_both(lv_obj_t *imgbtn, const void *src) { + lv_imgbtn_set_src(imgbtn, LV_BTN_STATE_REL, src); + lv_imgbtn_set_src(imgbtn, LV_BTN_STATE_PR, src); +} + +// Use label style for the image button +void lv_imgbtn_use_label_style(lv_obj_t *imgbtn) { + lv_imgbtn_set_style(imgbtn, LV_BTN_STATE_REL, &tft_style_label_rel); + lv_imgbtn_set_style(imgbtn, LV_BTN_STATE_PR, &tft_style_label_pre); +} + +// Use label style for the button +void lv_btn_use_label_style(lv_obj_t *btn) { + lv_btn_set_style(btn, LV_BTN_STYLE_REL, &tft_style_label_rel); + lv_btn_set_style(btn, LV_BTN_STYLE_PR, &tft_style_label_pre); +} + +// Use button style for the button +void lv_btn_use_button_style(lv_obj_t *btn) { + lv_btn_set_style(btn, LV_BTN_STYLE_REL, &style_btn_rel); + lv_btn_set_style(btn, LV_BTN_STYLE_PR, &style_btn_pr); +} + +// Use a single style for both Released and Pressed +void lv_btn_set_style_both(lv_obj_t *btn, lv_style_t *style) { + lv_btn_set_style(btn, LV_BTN_STYLE_REL, style); + lv_btn_set_style(btn, LV_BTN_STYLE_PR, style); +} + +// Create a screen +lv_obj_t* lv_screen_create(DISP_STATE newScreenType, const char* title) { + lv_obj_t *scr = lv_obj_create(nullptr, nullptr); + lv_obj_set_style(scr, &tft_style_scr); + lv_scr_load(scr); + lv_obj_clean(scr); + + // breadcrumbs + if (disp_state_stack._disp_state[disp_state_stack._disp_index] != newScreenType) { + disp_state_stack._disp_index++; + disp_state_stack._disp_state[disp_state_stack._disp_index] = newScreenType; + } + disp_state = newScreenType; + + // title + lv_obj_t *titleLabel = nullptr; + if (!title) + titleLabel = lv_label_create(scr, TITLE_XPOS, TITLE_YPOS, creat_title_text()); + else if (title[0] != '\0') + titleLabel = lv_label_create(scr, TITLE_XPOS, TITLE_YPOS, title); + if (titleLabel) + lv_obj_set_style(titleLabel, &tft_style_label_rel); + + lv_refr_now(lv_refr_get_disp_refreshing()); + + return scr; +} + +// Create an empty label +lv_obj_t* lv_label_create_empty(lv_obj_t *par) { + lv_obj_t *label = lv_label_create(par, (lv_obj_t*)nullptr); + return label; +} + +// Create a label with style and text +lv_obj_t* lv_label_create(lv_obj_t *par, const char *text) { + lv_obj_t *label = lv_label_create_empty(par); + if (text) lv_label_set_text(label, text); + lv_obj_set_style(label, &tft_style_label_rel); + return label; +} + +// Create a label with style, position, and text +lv_obj_t* lv_label_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, const char *text) { + lv_obj_t *label = lv_label_create(par, text); + lv_obj_set_pos(label, x, y); + return label; +} + +// Create a button with callback, ID, and Style. +lv_obj_t* lv_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id/*=0*/, lv_style_t *style/*=&style_para_value*/) { + lv_obj_t *btn = lv_btn_create(par, nullptr); + if (id) + lv_obj_set_event_cb_mks(btn, cb, id, "", 0); + else + lv_obj_set_event_cb(btn, cb); + lv_btn_set_style_both(btn, style); + return btn; +} + +// Create a button with callback and ID, with label style. +lv_obj_t* lv_label_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id/*=0*/) { + lv_obj_t *btn = lv_btn_create(par, cb, id, nullptr); + lv_btn_use_label_style(btn); + return btn; +} + +// Create a button with callback and ID, with button style. +lv_obj_t* lv_button_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id/*=0*/) { + lv_obj_t *btn = lv_btn_create(par, cb, id, nullptr); + lv_btn_use_button_style(btn); + return btn; +} + +// Create a button with position, size, callback, ID, and style. +lv_obj_t* lv_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id, lv_style_t *style) { + lv_obj_t *btn = lv_btn_create(par, cb, id, style); + lv_obj_set_pos(btn, x, y); + lv_obj_set_size(btn, w, h); + return btn; +} + +// Create a button with position, size, callback, and ID. Style set to style_para_value. +lv_obj_t* lv_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id/*=0*/) { + lv_obj_t *btn = lv_btn_create(par, x, y, w, h, cb, id, &style_para_value); + return btn; +} + +// Create a button with position, size, callback, and ID, with label style. +lv_obj_t* lv_label_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id/*=0*/) { + lv_obj_t *btn = lv_label_btn_create(par, cb, id); + lv_obj_set_pos(btn, x, y); + lv_obj_set_size(btn, w, h); + return btn; +} + +// Create a button with position, size, callback, and ID, with label style. +lv_obj_t* lv_button_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id/*=0*/) { + lv_obj_t *btn = lv_button_btn_create(par, cb, id); + lv_obj_set_pos(btn, x, y); + lv_obj_set_size(btn, w, h); + return btn; +} + +// Create a button with callback and ID. Style set to style_para_back. +lv_obj_t* lv_btn_create_back(lv_obj_t *par, lv_event_cb_t cb, const int id/*=0*/) { + return lv_btn_create(par, cb, id, &style_para_back); +} +// Create a button with position, size, callback, and ID. Style set to style_para_back. +lv_obj_t* lv_btn_create_back(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id/*=0*/) { + lv_obj_t *btn = lv_btn_create_back(par, cb, id); + lv_obj_set_pos(btn, x, y); + lv_obj_set_size(btn, w, h); + return btn; +} + +// Create an image button with image, callback, and ID. Use label style. +lv_obj_t* lv_imgbtn_create(lv_obj_t *par, const char *img, lv_event_cb_t cb, const int id/*=0*/) { + lv_obj_t *btn = lv_imgbtn_create(par, nullptr); + if (img) lv_imgbtn_set_src_both(btn, img); + if (id) + lv_obj_set_event_cb_mks(btn, cb, id, "", 0); + else + lv_obj_set_event_cb(btn, cb); + lv_imgbtn_use_label_style(btn); + lv_btn_set_layout(btn, LV_LAYOUT_OFF); + return btn; +} + +// Create an image button with image, position, callback, and ID. Use label style. +lv_obj_t* lv_imgbtn_create(lv_obj_t *par, const char *img, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id/*=0*/) { + lv_obj_t *btn = lv_imgbtn_create(par, img, cb, id); + lv_obj_set_pos(btn, x, y); + return btn; +} + +lv_obj_t* lv_big_button_create(lv_obj_t *par, const char *img, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, bool centerLabel) { + lv_obj_t *btn = lv_imgbtn_create(par, img, cb, id); + lv_obj_set_pos(btn, x, y); + lv_obj_t *label = lv_label_create_empty(btn); + if (gCfgItems.multiple_language) { + lv_label_set_text(label, text); + if (centerLabel) + lv_obj_align(label, btn, LV_ALIGN_CENTER, 0, 0); + else + lv_obj_align(label, btn, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) + lv_group_add_obj(g, btn); + return btn; +} + +lv_obj_t* lv_screen_menu_item(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, bool drawArrow) { + lv_obj_t *btn = lv_btn_create(par, nullptr); /*Add a button the current screen*/ + lv_obj_set_pos(btn, x, y); /*Set its position*/ + lv_obj_set_size(btn, PARA_UI_SIZE_X, PARA_UI_SIZE_Y); /*Set its size*/ + if (id > -1) lv_obj_set_event_cb_mks(btn, cb, id, "", 0); + lv_btn_use_label_style(btn); + lv_btn_set_layout(btn, LV_LAYOUT_OFF); + lv_obj_t *label = lv_label_create_empty(btn); /*Add a label to the button*/ + if (gCfgItems.multiple_language) { + lv_label_set_text(label, text); + lv_obj_align(label, btn, LV_ALIGN_IN_LEFT_MID, PARA_UI_ITEM_TEXT_H, 0); + } + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) + lv_group_add_obj(g, btn); + + if (drawArrow) (void)lv_imgbtn_create(par, "F:/bmp_arrow.bin", x + PARA_UI_SIZE_X, y + PARA_UI_ARROW_V, cb, id); + + lv_obj_t *line1 = lv_line_create(par, nullptr); + lv_ex_line(line1, line_points[index]); + + return btn; +} + +lv_obj_t* lv_screen_menu_item_onoff(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const bool curValue) { + lv_label_create(par, x + PARA_UI_ITEM_TEXT_H, y + PARA_UI_ITEM_TEXT_V, text); + + lv_obj_t* btnValue = lv_imgbtn_create(par, curValue ? "F:/bmp_enable.bin" : "F:/bmp_disable.bin", PARA_UI_STATE_POS_X, y + PARA_UI_STATE_V, cb, id); + lv_obj_t* labelValue = lv_label_create_empty(btnValue); + lv_label_set_text(labelValue, curValue ? machine_menu.enable : machine_menu.disable); + lv_obj_align(labelValue, btnValue, LV_ALIGN_CENTER, 0, 0); + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, btnValue); + lv_obj_t *line1 = lv_line_create(par, nullptr); + lv_ex_line(line1, line_points[index]); + return btnValue; +} + +void lv_screen_menu_item_1_edit(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const char *editValue) { + lv_label_create(par, x + PARA_UI_ITEM_TEXT_H, y + PARA_UI_ITEM_TEXT_V, text); + + lv_obj_t* btnValue = lv_btn_create(par, PARA_UI_VALUE_POS_X, y + PARA_UI_VALUE_V, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE, cb, id); + lv_obj_t* labelValue = lv_label_create_empty(btnValue); + lv_label_set_text(labelValue, editValue); + lv_obj_align(labelValue, btnValue, LV_ALIGN_CENTER, 0, 0); + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, btnValue); + + lv_obj_t *line1 = lv_line_create(par, nullptr); + lv_ex_line(line1, line_points[index]); +} + +void lv_screen_menu_item_2_edit(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const char *editValue, const int idEdit2, const char *editValue2) { + lv_label_create(par, x + PARA_UI_ITEM_TEXT_H, y + PARA_UI_ITEM_TEXT_V, text); + + lv_obj_t* btnValue = lv_btn_create(par, PARA_UI_VALUE_POS_X_2, y + PARA_UI_VALUE_V_2, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE, cb, idEdit2); + lv_obj_t* labelValue = lv_label_create_empty(btnValue); + lv_label_set_text(labelValue, editValue2); + lv_obj_align(labelValue, btnValue, LV_ALIGN_CENTER, 0, 0); + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, btnValue); + + btnValue = lv_btn_create(par, PARA_UI_VALUE_POS_X, y + PARA_UI_VALUE_V, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE, cb, id); + labelValue = lv_label_create_empty(btnValue); + lv_label_set_text(labelValue, editValue); + lv_obj_align(labelValue, btnValue, LV_ALIGN_CENTER, 0, 0); + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, btnValue); + + lv_obj_t *line1 = lv_line_create(par, nullptr); + lv_ex_line(line1, line_points[index]); +} + +void lv_screen_menu_item_onoff_update(lv_obj_t *btn, const bool curValue) { + lv_imgbtn_set_src_both(btn, curValue ? "F:/bmp_enable.bin" : "F:/bmp_disable.bin"); + lv_label_set_text((lv_obj_t*)btn->child_ll.head, curValue ? machine_menu.enable : machine_menu.disable); +} + +void lv_screen_menu_item_turn_page(lv_obj_t *par, const char *text, lv_event_cb_t cb, const int id) { + lv_obj_t* btnTurnPage = lv_btn_create(par, PARA_UI_TURN_PAGE_POS_X, PARA_UI_TURN_PAGE_POS_Y, PARA_UI_TURN_BTN_X_SIZE, PARA_UI_TURN_BTN_Y_SIZE, cb, id); + lv_obj_t* labelTurnPage = lv_label_create_empty(btnTurnPage); + lv_btn_set_style_both(btnTurnPage, &style_para_back); + lv_label_set_text(labelTurnPage, text); + lv_obj_align(labelTurnPage, btnTurnPage, LV_ALIGN_CENTER, 0, 0); + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) + lv_group_add_obj(g, btnTurnPage); +} + +void lv_screen_menu_item_return(lv_obj_t *par, lv_event_cb_t cb, const int id) { + lv_obj_t* btnReturn = lv_btn_create(par, PARA_UI_BACL_POS_X, PARA_UI_BACL_POS_Y, PARA_UI_BACK_BTN_X_SIZE, PARA_UI_BACK_BTN_Y_SIZE, cb, id); + lv_obj_t* labelReturn = lv_label_create_empty(btnReturn); + lv_btn_set_style_both(btnReturn, &style_para_back); + lv_label_set_text(labelReturn, common_menu.text_back); + lv_obj_align(labelReturn, btnReturn, LV_ALIGN_CENTER, 0, 0); + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) + lv_group_add_obj(g, btnReturn); +} + +#if ENABLED(SDSUPPORT) + + void sd_detection() { + static bool last_sd_status; + const bool sd_status = IS_SD_INSERTED(); + if (sd_status != last_sd_status) { + last_sd_status = sd_status; + if (sd_status) card.mount(); else card.release(); + } + } + +#endif + +void lv_ex_line(lv_obj_t *line, lv_point_t *points) { + // Copy the previous line and apply the new style + lv_line_set_points(line, points, 2); // Set the points + lv_line_set_style(line, LV_LINE_STYLE_MAIN, &style_line); + lv_obj_align(line, nullptr, LV_ALIGN_IN_TOP_MID, 0, 0); +} + +extern volatile uint32_t systick_uptime_millis; + +void print_time_count() { + if ((systick_uptime_millis % 1000) == 0) + if (print_time.start == 1) print_time.seconds++; +} + +void lv_print_finished() { + if (once_flag == 0) { + stop_print_time(); + + flash_preview_begin = false; + default_preview_flg = false; + lv_clear_cur_ui(); + lv_draw_dialog(DIALOG_TYPE_FINISH_PRINT); + + once_flag = true; + + #if HAS_SUICIDE + if (gCfgItems.finish_power_off) { + gcode.process_subcommands_now_P(PSTR("M1001")); + queue.inject_P(PSTR("M81")); + marlin_state = MF_RUNNING; + } + #endif + uiCfg.print_state = IDLE; + } +} + +void LV_TASK_HANDLER() { + lv_task_handler(); + if (mks_test_flag == 0x1E) mks_hardware_test(); + + TERN_(HAS_GCODE_PREVIEW, disp_pre_gcode(2, 36)); + + GUI_RefreshPage(); + + TERN_(MKS_WIFI_MODULE, get_wifi_commands()); + + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_update_encoder(); + #endif + if (marlin_state == MF_SD_COMPLETE) lv_print_finished(); +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h new file mode 100644 index 0000000..5f27123 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_ui.h @@ -0,0 +1,551 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include <lvgl.h> + +#include <stdint.h> +#include <string.h> + +// the colors of the last MKS Ui +#undef LV_COLOR_BACKGROUND +#define LV_COLOR_BACKGROUND LV_COLOR_MAKE(0x1A, 0x1A, 0x1A) + +#define TFT_LV_PARA_BACK_BODY_COLOR LV_COLOR_MAKE(0x4A, 0x52, 0xFF) + +#include "tft_lvgl_configuration.h" +#include "tft_multi_language.h" +#include "pic_manager.h" +#include "draw_ready_print.h" +#include "draw_language.h" +#include "draw_set.h" +#include "draw_tool.h" +#include "draw_print_file.h" +#include "draw_dialog.h" +#include "draw_printing.h" +#include "draw_operation.h" +#include "draw_preHeat.h" +#include "draw_extrusion.h" +#include "draw_home.h" +#include "draw_more.h" +#include "draw_move_motor.h" +#include "draw_fan.h" +#include "draw_about.h" +#include "draw_change_speed.h" +#include "draw_manuaLevel.h" +#include "draw_error_message.h" +#include "printer_operation.h" +#include "draw_machine_para.h" +#include "draw_machine_settings.h" +#include "draw_motor_settings.h" +#include "draw_advance_settings.h" +#include "draw_acceleration_settings.h" +#include "draw_number_key.h" +#include "draw_jerk_settings.h" +#include "draw_pause_position.h" +#include "draw_step_settings.h" +#include "draw_tmc_current_settings.h" +#include "draw_eeprom_settings.h" +#include "draw_max_feedrate_settings.h" +#include "draw_tmc_step_mode_settings.h" +#include "draw_level_settings.h" +#include "draw_manual_level_pos_settings.h" +#include "draw_auto_level_offset_settings.h" +#include "draw_filament_change.h" +#include "draw_filament_settings.h" +#include "draw_homing_sensitivity_settings.h" +#include "draw_baby_stepping.h" +#include "draw_keyboard.h" +#include "draw_encoder_settings.h" +#include "draw_touchmi_settings.h" +#include "draw_bltouch_settings.h" + +#include "../../../../inc/MarlinConfigPre.h" + +#if ENABLED(MKS_WIFI_MODULE) + #include "wifiSerial.h" + #include "wifi_module.h" + #include "wifi_upload.h" + #include "draw_wifi_settings.h" + #include "draw_wifi.h" + #include "draw_wifi_list.h" + #include "draw_wifi_tips.h" + #include "draw_cloud_bind.h" +#endif + +#define ESP_WIFI 0x02 +#define AP_MODEL 0x01 +#define STA_MODEL 0x02 + +#define FILE_SYS_USB 0 +#define FILE_SYS_SD 1 + +#define TICK_CYCLE 1 + +#define PARA_SEL_ICON_TEXT_COLOR LV_COLOR_MAKE(0x4A, 0x52, 0xFF); + +#define TFT35 + +#ifdef TFT35 + + #define TFT_WIDTH 480 + #define TFT_HEIGHT 320 + + #define titleHeight 36 // TFT_screen.title_high + #define INTERVAL_H 2 // TFT_screen.gap_h // 2 + #define INTERVAL_V 2 // TFT_screen.gap_v // 2 + #define BTN_X_PIXEL 117 // TFT_screen.btn_x_pixel + #define BTN_Y_PIXEL 140 // TFT_screen.btn_y_pixel + + #define SIMPLE_FIRST_PAGE_GRAP 30 + + #define BUTTON_TEXT_Y_OFFSET -20 + + #define TITLE_XPOS 3 // TFT_screen.title_xpos + #define TITLE_YPOS 5 // TFT_screen.title_ypos + + #define FILE_BTN_CNT 6 + + #define OTHER_BTN_XPIEL 117 + #define OTHER_BTN_YPIEL 92 + + #define FILE_PRE_PIC_X_OFFSET 8 + #define FILE_PRE_PIC_Y_OFFSET 0 + + #define PREVIEW_LITTLE_PIC_SIZE 40910 // 400*100+9*101+1 + #define PREVIEW_SIZE 202720 // (PREVIEW_LITTLE_PIC_SIZE+800*200+201*9+1) + + // machine parameter ui + #define PARA_UI_POS_X 10 + #define PARA_UI_POS_Y 50 + + #define PARA_UI_SIZE_X 450 + #define PARA_UI_SIZE_Y 40 + + #define PARA_UI_ARROW_V 12 + #define PARA_UI_ITEM_TEXT_V 10 + #define PARA_UI_ITEM_TEXT_H 10 + + #define PARA_UI_BACL_POS_X 400 + #define PARA_UI_BACL_POS_Y 270 + + #define PARA_UI_TURN_PAGE_POS_X 320 + #define PARA_UI_TURN_PAGE_POS_Y 270 + + #define PARA_UI_VALUE_SIZE_X 370 + #define PARA_UI_VALUE_POS_X 400 + #define PARA_UI_VALUE_V 5 + + #define PARA_UI_STATE_POS_X 380 + #define PARA_UI_STATE_V 2 + + #define PARA_UI_VALUE_SIZE_X_2 200 + #define PARA_UI_VALUE_POS_X_2 320 + #define PARA_UI_VALUE_V_2 5 + + #define PARA_UI_VALUE_BTN_X_SIZE 70 + #define PARA_UI_VALUE_BTN_Y_SIZE 28 + + #define PARA_UI_TURN_BTN_X_SIZE 70 + #define PARA_UI_TURN_BTN_Y_SIZE 40 + + #define PARA_UI_BACK_BTN_X_SIZE 70 + #define PARA_UI_BACK_BTN_Y_SIZE 40 + + #define QRCODE_X 20 + #define QRCODE_Y 40 + #define QRCODE_WIDTH 160 + +#else // ifdef TFT35 + + #define TFT_WIDTH 320 + #define TFT_HEIGHT 240 + +#endif // ifdef TFT35 + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern char public_buf_m[100]; +extern char public_buf_l[30]; + +typedef struct { + uint32_t spi_flash_flag; + uint8_t disp_rotation_180; + bool multiple_language; + uint8_t language; + uint8_t leveling_mode; + bool from_flash_pic; + bool finish_power_off; + bool pause_reprint; + uint8_t wifi_mode_sel; + uint8_t fileSysType; + uint8_t wifi_type; + bool cloud_enable; + bool encoder_enable; + int levelingPos[5][2]; + int filamentchange_load_length; + int filamentchange_load_speed; + int filamentchange_unload_length; + int filamentchange_unload_speed; + int filament_limit_temper; + float pausePosX; + float pausePosY; + float pausePosZ; + uint32_t curFilesize; +} CFG_ITMES; + +typedef struct { + uint8_t curTempType:1, + curSprayerChoose:3, + stepHeat:4; + uint8_t leveling_first_time:1, + para_ui_page:1, + configWifi:1, + command_send:1, + filament_load_heat_flg:1, + filament_heat_completed_load:1, + filament_unload_heat_flg:1, + filament_heat_completed_unload:1; + uint8_t filament_loading_completed:1, + filament_unloading_completed:1, + filament_loading_time_flg:1, + filament_unloading_time_flg:1, + curSprayerChoose_bak:4; + uint8_t tmc_connect_state:1; + uint8_t wifi_name[32]; + uint8_t wifi_key[64]; + uint8_t cloud_hostUrl[96]; + uint8_t extruStep; + uint8_t extruSpeed; + uint8_t print_state; + uint8_t stepPrintSpeed; + uint8_t waitEndMoves; + uint8_t dialogType; + uint8_t F[4]; + uint8_t filament_rate; + uint16_t moveSpeed; + uint16_t cloud_port; + uint16_t moveSpeed_bak; + uint32_t totalSend; + uint32_t filament_loading_time; + uint32_t filament_unloading_time; + uint32_t filament_loading_time_cnt; + uint32_t filament_unloading_time_cnt; + float move_dist; + float desireSprayerTempBak; + float current_x_position_bak; + float current_y_position_bak; + float current_z_position_bak; + float current_e_position_bak; +} UI_CFG; + +typedef enum { + MAIN_UI, + PRINT_READY_UI, + PRINT_FILE_UI, + PRINTING_UI, + MOVE_MOTOR_UI, + OPERATE_UI, + PAUSE_UI, + EXTRUSION_UI, + FAN_UI, + PRE_HEAT_UI, + CHANGE_SPEED_UI, + TEMP_UI, + SET_UI, + ZERO_UI, + BLTOUCH_UI, + TOUCHMI_UI, + SPRAYER_UI, + MACHINE_UI, + LANGUAGE_UI, + ABOUT_UI, + LOG_UI, + DISK_UI, + CALIBRATE_UI, + DIALOG_UI, + WIFI_UI, + MORE_UI, + FILETRANSFER_UI, + FILETRANSFERSTATE_UI, + PRINT_MORE_UI, + FILAMENTCHANGE_UI, + LEVELING_UI, + MESHLEVELING_UI, + BIND_UI, + #if HAS_BED_PROBE + NOZZLE_PROBE_OFFSET_UI, + #endif + TOOL_UI, + HARDWARE_TEST_UI, + WIFI_LIST_UI, + KEY_BOARD_UI, + WIFI_TIPS_UI, + MACHINE_PARA_UI, + MACHINE_SETTINGS_UI, + TEMPERATURE_SETTINGS_UI, + MOTOR_SETTINGS_UI, + MACHINETYPE_UI, + STROKE_UI, + HOME_DIR_UI, + ENDSTOP_TYPE_UI, + FILAMENT_SETTINGS_UI, + LEVELING_SETTIGNS_UI, + LEVELING_PARA_UI, + DELTA_LEVELING_PARA_UI, + MANUAL_LEVELING_POSIGION_UI, + MAXFEEDRATE_UI, + STEPS_UI, + ACCELERATION_UI, + JERK_UI, + MOTORDIR_UI, + HOMESPEED_UI, + NOZZLE_CONFIG_UI, + HOTBED_CONFIG_UI, + ADVANCED_UI, + DOUBLE_Z_UI, + ENABLE_INVERT_UI, + NUMBER_KEY_UI, + BABY_STEP_UI, + ERROR_MESSAGE_UI, + PAUSE_POS_UI, + TMC_CURRENT_UI, + TMC_MODE_UI, + EEPROM_SETTINGS_UI, + WIFI_SETTINGS_UI, + HOMING_SENSITIVITY_UI, + ENCODER_SETTINGS_UI, + TOUCH_CALIBRATION_UI +} DISP_STATE; + +typedef struct { + DISP_STATE _disp_state[100]; + int _disp_index; +} DISP_STATE_STACK; + +typedef struct { + int16_t days; + uint16_t hours; + uint8_t minutes; + volatile int8_t seconds; + int8_t ms_10; + int8_t start; +} PRINT_TIME; +extern PRINT_TIME print_time; + +typedef enum { + PrintAcceleration, + RetractAcceleration, + TravelAcceleration, + XAcceleration, + YAcceleration, + ZAcceleration, + E0Acceleration, + E1Acceleration, + + XMaxFeedRate, + YMaxFeedRate, + ZMaxFeedRate, + E0MaxFeedRate, + E1MaxFeedRate, + + XJerk, + YJerk, + ZJerk, + EJerk, + + Xstep, + Ystep, + Zstep, + E0step, + E1step, + + Xcurrent, + Ycurrent, + Zcurrent, + E0current, + E1current, + + pause_pos_x, + pause_pos_y, + pause_pos_z, + + level_pos_x1, + level_pos_y1, + level_pos_x2, + level_pos_y2, + level_pos_x3, + level_pos_y3, + level_pos_x4, + level_pos_y4, + level_pos_x5, + level_pos_y5, + #if HAS_BED_PROBE + x_offset, + y_offset, + z_offset, + #endif + load_length, + load_speed, + unload_length, + unload_speed, + filament_temp, + + x_sensitivity, + y_sensitivity, + z_sensitivity, + z2_sensitivity +} num_key_value_state; +extern num_key_value_state value; + +typedef enum { + wifiName, + wifiPassWord, + wifiConfig, + gcodeCommand +} keyboard_value_state; +extern keyboard_value_state keyboard_value; + +extern CFG_ITMES gCfgItems; +extern UI_CFG uiCfg; +extern DISP_STATE disp_state; +extern DISP_STATE last_disp_state; +extern DISP_STATE_STACK disp_state_stack; + +extern lv_style_t tft_style_scr; +extern lv_style_t tft_style_label_pre; +extern lv_style_t tft_style_label_rel; +extern lv_style_t style_line; +extern lv_style_t style_para_value_pre; +extern lv_style_t style_para_value_rel; +extern lv_style_t style_num_key_pre; +extern lv_style_t style_num_key_rel; +extern lv_style_t style_num_text; +extern lv_style_t style_sel_text; +extern lv_style_t style_para_value; +extern lv_style_t style_para_back; +extern lv_style_t lv_bar_style_indic; +extern lv_style_t style_btn_pr; +extern lv_style_t style_btn_rel; + +extern lv_point_t line_points[4][2]; + +extern void gCfgItems_init(); +extern void ui_cfg_init(); +extern void tft_style_init(); +extern char *creat_title_text(void); +extern void preview_gcode_prehandle(char *path); +extern void update_spi_flash(); +extern void update_gcode_command(int addr,uint8_t *s); +extern void get_gcode_command(int addr,uint8_t *d); +#if HAS_GCODE_PREVIEW + extern void disp_pre_gcode(int xpos_pixel, int ypos_pixel); +#endif +extern void GUI_RefreshPage(); +extern void lv_clear_cur_ui(); +extern void lv_draw_return_ui(); +extern void sd_detection(); +extern void gCfg_to_spiFlah(); +extern void print_time_count(); + +extern void LV_TASK_HANDLER(); +extern void lv_ex_line(lv_obj_t *line, lv_point_t *points); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif + +// Set the same image for both Released and Pressed +void lv_imgbtn_set_src_both(lv_obj_t *imgbtn, const void *src); + +// Set label styles for Released and Pressed +void lv_imgbtn_use_label_style(lv_obj_t *imgbtn); + +// Set label styles for Released and Pressed +void lv_btn_use_label_style(lv_obj_t *btn); + +// Set the same style for both Released and Pressed +void lv_btn_set_style_both(lv_obj_t *btn, lv_style_t *style); + +// Create a screen +lv_obj_t* lv_screen_create(DISP_STATE newScreenType, const char* title = nullptr); + +// Create an empty label +lv_obj_t* lv_label_create_empty(lv_obj_t *par); + +// Create a label with style and text +lv_obj_t* lv_label_create(lv_obj_t *par, const char *text); + +// Create a label with style, position, and text +lv_obj_t* lv_label_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, const char *text); + +// Create a button with callback, ID, and Style. +lv_obj_t* lv_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id, lv_style_t *style=&style_para_value); + +// Create a button with callback and ID, with label style. +lv_obj_t* lv_label_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id=0); + +// Create a button with callback and ID, with button style. +lv_obj_t* lv_button_btn_create(lv_obj_t *par, lv_event_cb_t cb, const int id=0); + +// Create a button with position, size, callback, ID, and style. +lv_obj_t* lv_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id, lv_style_t *style); + +// Create a button with position, size, callback, and ID. Style set to style_para_value. +lv_obj_t* lv_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id=0); + +// Create a button with position, size, callback, and ID, with label style. +lv_obj_t* lv_label_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id=0); + +// Create a button with position, size, callback, and ID, with button style. +lv_obj_t* lv_button_btn_create(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id=0); + +// Create a button with callback and ID. Style set to style_para_back. +lv_obj_t* lv_btn_create_back(lv_obj_t *par, lv_event_cb_t cb, const int id=0); + +// Create a button with position, size, callback, and ID. Style set to style_para_back. +lv_obj_t* lv_btn_create_back(lv_obj_t *par, lv_coord_t x, lv_coord_t y, lv_coord_t w, lv_coord_t h, lv_event_cb_t cb, const int id=0); + +// Create an image button with image, callback, and ID. Use label style. +lv_obj_t* lv_imgbtn_create(lv_obj_t *par, const char *img, lv_event_cb_t cb, const int id=0); + +// Create an image button with image, position, callback, and ID. Use label style. +lv_obj_t* lv_imgbtn_create(lv_obj_t *par, const char *img, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id=0); + +// Create a big image button with a label, follow the LVGL UI standard. +lv_obj_t* lv_big_button_create(lv_obj_t *par, const char *img, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, bool centerLabel = false); + +// Create a menu item, follow the LVGL UI standard. +lv_obj_t* lv_screen_menu_item(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, bool drawArrow = true); + +lv_obj_t* lv_screen_menu_item_onoff(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const bool curValue); + +void lv_screen_menu_item_1_edit(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const char *editValue); +void lv_screen_menu_item_2_edit(lv_obj_t *par, const char *text, lv_coord_t x, lv_coord_t y, lv_event_cb_t cb, const int id, const int index, const char *editValue, const int idEdit2, const char *editValue2); +void lv_screen_menu_item_onoff_update(lv_obj_t *btn, const bool curValue); +void lv_screen_menu_item_turn_page(lv_obj_t *par, const char *text, lv_event_cb_t cb, const int id); +void lv_screen_menu_item_return(lv_obj_t *par, lv_event_cb_t cb, const int id); + +#define _DIA_1(T) (uiCfg.dialogType == DIALOG_##T) +#define DIALOG_IS(V...) DO(DIA,||,V) diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.cpp new file mode 100644 index 0000000..416905e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.cpp @@ -0,0 +1,166 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include <lv_conf.h> +#include "tft_lvgl_configuration.h" + +#if ENABLED(MKS_WIFI_MODULE) + +#include "draw_ui.h" + +extern lv_group_t *g; +static lv_obj_t *scr, *wifi_name_text, *wifi_key_text, *wifi_state_text, *wifi_ip_text; + +enum { + ID_W_RETURN = 1, + ID_W_CLOUD, + ID_W_RECONNECT +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + lv_clear_cur_ui(); + switch (obj->mks_obj_id) { + case ID_W_RETURN: + lv_draw_set(); + break; + case ID_W_CLOUD: + lv_draw_cloud_bind(); + break; + #if ENABLED(MKS_WIFI_MODULE) + case ID_W_RECONNECT: { + uint8_t cmd_wifi_list[] = { 0xA5, 0x07, 0x00, 0x00, 0xFC }; + raw_send_to_wifi(cmd_wifi_list, COUNT(cmd_wifi_list)); + lv_draw_wifi_list(); + } break; + #endif + } +} + +void lv_draw_wifi(void) { + scr = lv_screen_create(WIFI_UI); + + lv_obj_t *buttonReconnect = nullptr, *label_Reconnect = nullptr; + lv_obj_t *buttonCloud = nullptr, *label_Cloud = nullptr; + + const bool enc_ena = TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable); + + if (gCfgItems.wifi_mode_sel == STA_MODEL) { + + if (gCfgItems.cloud_enable) + buttonCloud = lv_imgbtn_create(scr, "F:/bmp_cloud.bin", BTN_X_PIXEL+INTERVAL_V*2, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_W_CLOUD); + + buttonReconnect = lv_imgbtn_create(scr, "F:/bmp_wifi.bin", BTN_X_PIXEL * 2 + INTERVAL_V * 3, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_W_RECONNECT); + + #if HAS_ROTARY_ENCODER + if (gCfgItems.cloud_enable) lv_group_add_obj(g, buttonCloud); + if (enc_ena) lv_group_add_obj(g, buttonReconnect); + #endif + + label_Reconnect = lv_label_create_empty(buttonReconnect); + if (gCfgItems.cloud_enable) label_Cloud = lv_label_create_empty(buttonCloud); + } + + // Create an Image button + lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_return.bin", BTN_X_PIXEL * 3 + INTERVAL_V * 4, BTN_Y_PIXEL + INTERVAL_H + titleHeight, event_handler, ID_W_RETURN); + if (enc_ena) lv_group_add_obj(g, buttonBack); + lv_obj_t *label_Back = lv_label_create_empty(buttonBack); + + if (gCfgItems.multiple_language) { + if (gCfgItems.wifi_mode_sel == STA_MODEL) { + if (gCfgItems.cloud_enable) { + lv_label_set_text(label_Cloud, wifi_menu.cloud); + lv_obj_align(label_Cloud, buttonCloud, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + lv_label_set_text(label_Reconnect, wifi_menu.reconnect); + lv_obj_align(label_Reconnect, buttonReconnect, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + lv_label_set_text(label_Back, common_menu.text_back); + lv_obj_align(label_Back, buttonBack, LV_ALIGN_IN_BOTTOM_MID, 0, BUTTON_TEXT_Y_OFFSET); + } + + wifi_ip_text = lv_label_create_empty(scr); + lv_obj_set_style(wifi_ip_text, &tft_style_label_rel); + wifi_name_text = lv_label_create_empty(scr); + lv_obj_set_style(wifi_name_text, &tft_style_label_rel); + wifi_key_text = lv_label_create_empty(scr); + lv_obj_set_style(wifi_key_text, &tft_style_label_rel); + wifi_state_text = lv_label_create_empty(scr); + lv_obj_set_style(wifi_state_text, &tft_style_label_rel); + + disp_wifi_state(); +} + +void disp_wifi_state() { + strcpy(public_buf_m, wifi_menu.ip); + strcat(public_buf_m, ipPara.ip_addr); + lv_label_set_text(wifi_ip_text, public_buf_m); + lv_obj_align(wifi_ip_text, nullptr, LV_ALIGN_CENTER, 0, -100); + + strcpy(public_buf_m, wifi_menu.wifi); + strcat(public_buf_m, wifiPara.ap_name); + lv_label_set_text(wifi_name_text, public_buf_m); + lv_obj_align(wifi_name_text, nullptr, LV_ALIGN_CENTER, 0, -70); + + if (wifiPara.mode == AP_MODEL) { + strcpy(public_buf_m, wifi_menu.key); + strcat(public_buf_m, wifiPara.keyCode); + lv_label_set_text(wifi_key_text, public_buf_m); + lv_obj_align(wifi_key_text, nullptr, LV_ALIGN_CENTER, 0, -40); + + strcpy(public_buf_m, wifi_menu.state_ap); + if (wifi_link_state == WIFI_CONNECTED) + strcat(public_buf_m, wifi_menu.connected); + else if (wifi_link_state == WIFI_NOT_CONFIG) + strcat(public_buf_m, wifi_menu.disconnected); + else + strcat(public_buf_m, wifi_menu.exception); + lv_label_set_text(wifi_state_text, public_buf_m); + lv_obj_align(wifi_state_text, nullptr, LV_ALIGN_CENTER, 0, -10); + } + else { + strcpy(public_buf_m, wifi_menu.state_sta); + if (wifi_link_state == WIFI_CONNECTED) + strcat(public_buf_m, wifi_menu.connected); + else if (wifi_link_state == WIFI_NOT_CONFIG) + strcat(public_buf_m, wifi_menu.disconnected); + else + strcat(public_buf_m, wifi_menu.exception); + lv_label_set_text(wifi_state_text, public_buf_m); + lv_obj_align(wifi_state_text, nullptr, LV_ALIGN_CENTER, 0, -40); + + lv_label_set_text(wifi_key_text, ""); + lv_obj_align(wifi_key_text, nullptr, LV_ALIGN_CENTER, 0, -10); + } +} + +void lv_clear_wifi() { + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) + lv_group_remove_all_objs(g); + lv_obj_del(scr); +} + +#endif // MKS_WIFI_MODULE +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.h new file mode 100644 index 0000000..966a84d --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi.h @@ -0,0 +1,38 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + + +extern void lv_draw_wifi(void); +extern void lv_clear_wifi(); +extern void disp_wifi_state(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif + + + diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.cpp new file mode 100644 index 0000000..b0f3848 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.cpp @@ -0,0 +1,177 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include <lv_conf.h> +#include "tft_lvgl_configuration.h" + +#if ENABLED(MKS_WIFI_MODULE) + +#include "draw_ui.h" + +#define NAME_BTN_X 330 +#define NAME_BTN_Y 48 + +#define MARK_BTN_X 0 +#define MARK_BTN_Y 68 + +WIFI_LIST wifi_list; +list_menu_def list_menu; + +extern lv_group_t *g; +static lv_obj_t *scr; +static lv_obj_t *buttonWifiN[NUMBER_OF_PAGE]; +static lv_obj_t *labelWifiText[NUMBER_OF_PAGE]; +static lv_obj_t *labelPageText; + +#define ID_WL_RETURN 11 +#define ID_WL_DOWN 12 + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + + if (obj->mks_obj_id == ID_WL_RETURN) { + lv_clear_cur_ui(); + lv_draw_set(); + } + else if (obj->mks_obj_id == ID_WL_DOWN) { + if (wifi_list.getNameNum > 0) { + if ((wifi_list.nameIndex + NUMBER_OF_PAGE) >= wifi_list.getNameNum) { + wifi_list.nameIndex = 0; + wifi_list.currentWifipage = 1; + } + else { + wifi_list.nameIndex += NUMBER_OF_PAGE; + wifi_list.currentWifipage++; + } + disp_wifi_list(); + } + } + else { + for (uint8_t i = 0; i < NUMBER_OF_PAGE; i++) { + if (obj->mks_obj_id == i + 1) { + if (wifi_list.getNameNum != 0) { + const bool do_wifi = wifi_link_state == WIFI_CONNECTED && strcmp((const char *)wifi_list.wifiConnectedName, (const char *)wifi_list.wifiName[wifi_list.nameIndex + i]) == 0; + wifi_list.nameIndex += i; + last_disp_state = WIFI_LIST_UI; + lv_clear_wifi_list(); + if (do_wifi) + lv_draw_wifi(); + else { + keyboard_value = wifiConfig; + lv_draw_keyboard(); + } + } + } + } + } +} + +void lv_draw_wifi_list(void) { + scr = lv_screen_create(WIFI_LIST_UI); + + lv_obj_t *buttonDown = lv_imgbtn_create(scr, "F:/bmp_pageDown.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + OTHER_BTN_YPIEL + INTERVAL_H, event_handler, ID_WL_DOWN); + lv_obj_t *buttonBack = lv_imgbtn_create(scr, "F:/bmp_back.bin", OTHER_BTN_XPIEL * 3 + INTERVAL_V * 4, titleHeight + (OTHER_BTN_YPIEL + INTERVAL_H) * 2, event_handler, ID_WL_RETURN); + + for (uint8_t i = 0; i < NUMBER_OF_PAGE; i++) { + buttonWifiN[i] = lv_label_btn_create(scr, 0, NAME_BTN_Y * i + 10 + titleHeight, NAME_BTN_X, NAME_BTN_Y, event_handler, i + 1); + labelWifiText[i] = lv_label_create_empty(buttonWifiN[i]); + #if HAS_ROTARY_ENCODER + uint8_t j = 0; + if (gCfgItems.encoder_enable) { + j = wifi_list.nameIndex + i; + if (j < wifi_list.getNameNum) lv_group_add_obj(g, buttonWifiN[i]); + } + #endif + } + + labelPageText = lv_label_create_empty(scr); + lv_obj_set_style(labelPageText, &tft_style_label_rel); + + wifi_list.nameIndex = 0; + wifi_list.currentWifipage = 1; + + if (wifi_link_state == WIFI_CONNECTED && wifiPara.mode == STA_MODEL) { + ZERO(wifi_list.wifiConnectedName); + memcpy(wifi_list.wifiConnectedName, wifiPara.ap_name, sizeof(wifi_list.wifiConnectedName)); + } + + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) { + lv_group_add_obj(g, buttonDown); + lv_group_add_obj(g, buttonBack); + } + #else + UNUSED(buttonDown); + UNUSED(buttonBack); + #endif + + disp_wifi_list(); +} + +void disp_wifi_list(void) { + int8_t tmpStr[WIFI_NAME_BUFFER_SIZE] = { 0 }; + uint8_t i, j; + + sprintf((char *)tmpStr, list_menu.file_pages, wifi_list.currentWifipage, wifi_list.getPage); + lv_label_set_text(labelPageText, (const char *)tmpStr); + lv_obj_align(labelPageText, nullptr, LV_ALIGN_CENTER, 50, -100); + + for (i = 0; i < NUMBER_OF_PAGE; i++) { + ZERO(tmpStr); + + j = wifi_list.nameIndex + i; + if (j >= wifi_list.getNameNum) { + lv_label_set_text(labelWifiText[i], (const char *)tmpStr); + lv_obj_align(labelWifiText[i], buttonWifiN[i], LV_ALIGN_IN_LEFT_MID, 20, 0); + } + else { + lv_label_set_text(labelWifiText[i], (char const *)wifi_list.wifiName[j]); + lv_obj_align(labelWifiText[i], buttonWifiN[i], LV_ALIGN_IN_LEFT_MID, 20, 0); + + const bool btext = (wifi_link_state == WIFI_CONNECTED && strcmp((const char *)wifi_list.wifiConnectedName, (const char *)wifi_list.wifiName[j]) == 0); + lv_btn_set_style(buttonWifiN[i], LV_BTN_STYLE_REL, btext ? &style_sel_text : &tft_style_label_rel); + } + } +} + +void wifi_scan_handle() { + if (!DIALOG_IS(WIFI_ENABLE_TIPS) || uiCfg.command_send != 1) return; + last_disp_state = DIALOG_UI; + lv_clear_dialog(); + if (wifi_link_state == WIFI_CONNECTED && wifiPara.mode != AP_MODEL) + lv_draw_wifi(); + else + lv_draw_wifi_list(); +} + +void lv_clear_wifi_list() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // MKS_WIFI_MODULE +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.h new file mode 100644 index 0000000..e2d9275 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_list.h @@ -0,0 +1,76 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +extern void lv_draw_wifi_list(); +extern void lv_clear_wifi_list(); +extern void disp_wifi_list(void); +extern void cutWifiName(char *name, int len,char *outStr); +extern void wifi_scan_handle(); + +#define NUMBER_OF_PAGE 5 + +#define WIFI_TOTAL_NUMBER 20 +#define WIFI_NAME_BUFFER_SIZE 33 + +typedef struct { + int8_t getNameNum; + int8_t nameIndex; + int8_t currentWifipage; + int8_t getPage; + int8_t RSSI[WIFI_TOTAL_NUMBER]; + uint8_t wifiName[WIFI_TOTAL_NUMBER][WIFI_NAME_BUFFER_SIZE]; + uint8_t wifiConnectedName[WIFI_NAME_BUFFER_SIZE]; +} WIFI_LIST; +extern WIFI_LIST wifi_list; + +typedef struct list_menu_disp { + const char *title; + const char *file_pages; +} list_menu_def; +extern list_menu_def list_menu; + +typedef struct keyboard_menu_disp { + const char *title; + const char *apply; + const char *password; + const char *letter; + const char *digital; + const char *symbol; + const char *space; +} keyboard_menu_def; +extern keyboard_menu_def keyboard_menu; + +typedef struct tips_menu_disp { + const char *joining; + const char *failedJoin; + const char *wifiConected; +} tips_menu_def; +extern tips_menu_def tips_menu; + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.cpp new file mode 100644 index 0000000..7c1b0af --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.cpp @@ -0,0 +1,141 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include <lv_conf.h> +#include "tft_lvgl_configuration.h" + +#if ENABLED(MKS_WIFI_MODULE) + +#include "draw_ui.h" + +extern lv_group_t *g; +static lv_obj_t *scr, *labelModelAP = nullptr, *buttonModelAP = nullptr, *labelModelSTA = nullptr, *buttonModelSTA = nullptr, *btnCloudState = nullptr; + +enum { + ID_WIFI_RETURN = 1, + ID_WIFI_AP, + ID_WIFI_STA, + ID_WIFI_NAME, + ID_WIFI_PASSWORD, + ID_WIFI_CLOUD, + ID_WIFI_CONFIG +}; + +static void event_handler(lv_obj_t *obj, lv_event_t event) { + if (event != LV_EVENT_RELEASED) return; + switch (obj->mks_obj_id) { + case ID_WIFI_RETURN: + lv_clear_wifi_settings(); + lv_draw_return_ui(); + break; + case ID_WIFI_AP: + if (gCfgItems.wifi_mode_sel == AP_MODEL) return; + gCfgItems.wifi_mode_sel = AP_MODEL; + lv_btn_set_style_both(buttonModelAP, &style_para_back); + lv_btn_set_style_both(buttonModelSTA, &style_para_value); + update_spi_flash(); + break; + case ID_WIFI_STA: + if (gCfgItems.wifi_mode_sel == STA_MODEL) return; + gCfgItems.wifi_mode_sel = STA_MODEL; + lv_btn_set_style_both(buttonModelSTA, &style_para_back); + lv_btn_set_style_both(buttonModelAP, &style_para_value); + update_spi_flash(); + break; + case ID_WIFI_NAME: + keyboard_value = wifiName; + lv_clear_wifi_settings(); + lv_draw_keyboard(); + break; + case ID_WIFI_PASSWORD: + keyboard_value = wifiPassWord; + lv_clear_wifi_settings(); + lv_draw_keyboard(); + break; + case ID_WIFI_CLOUD: + gCfgItems.cloud_enable ^= true; + lv_screen_menu_item_onoff_update(btnCloudState, gCfgItems.cloud_enable); + update_spi_flash(); + break; + case ID_WIFI_CONFIG: + lv_clear_wifi_settings(); + lv_draw_dialog(DIALOG_WIFI_CONFIG_TIPS); + break; + } +} + +void lv_draw_wifi_settings(void) { + scr = lv_screen_create(WIFI_SETTINGS_UI, machine_menu.WifiConfTitle); + + lv_label_create(scr, PARA_UI_POS_X + PARA_UI_ITEM_TEXT_H, PARA_UI_POS_Y + 10, machine_menu.wifiMode); + buttonModelAP = lv_btn_create(scr, nullptr); + lv_obj_set_pos(buttonModelAP, PARA_UI_VALUE_POS_X_2, PARA_UI_POS_Y + PARA_UI_VALUE_V_2); + lv_obj_set_size(buttonModelAP, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE); + lv_obj_set_event_cb_mks(buttonModelAP, event_handler, ID_WIFI_AP, "", 0); + lv_btn_use_label_style(buttonModelAP); + lv_btn_set_layout(buttonModelAP, LV_LAYOUT_OFF); + lv_btn_set_style_both(buttonModelAP, gCfgItems.wifi_mode_sel == AP_MODEL ? &style_para_back : &style_para_value); + labelModelAP = lv_label_create_empty(buttonModelAP); + lv_label_set_text(labelModelAP, WIFI_AP_TEXT); + lv_obj_align(labelModelAP, buttonModelAP, LV_ALIGN_CENTER, 0, 0); + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, buttonModelAP); + + buttonModelSTA = lv_btn_create(scr, nullptr); + lv_obj_set_pos(buttonModelSTA, PARA_UI_VALUE_POS_X, PARA_UI_POS_Y + PARA_UI_VALUE_V); + lv_obj_set_size(buttonModelSTA, PARA_UI_VALUE_BTN_X_SIZE, PARA_UI_VALUE_BTN_Y_SIZE); + lv_obj_set_event_cb_mks(buttonModelSTA, event_handler, ID_WIFI_STA, "", 0); + lv_btn_use_label_style(buttonModelSTA); + lv_btn_set_layout(buttonModelSTA, LV_LAYOUT_OFF); + labelModelSTA = lv_label_create_empty(buttonModelSTA); + lv_btn_set_style_both(buttonModelSTA, gCfgItems.wifi_mode_sel == STA_MODEL ? &style_para_back : &style_para_value); + lv_label_set_text(labelModelSTA, WIFI_STA_TEXT); + lv_obj_align(labelModelSTA, buttonModelSTA, LV_ALIGN_CENTER, 0, 0); + if (TERN0(HAS_ROTARY_ENCODER, gCfgItems.encoder_enable)) lv_group_add_obj(g, buttonModelSTA); + + lv_obj_t *line1 = lv_line_create(scr, nullptr); + lv_ex_line(line1, line_points[0]); + + strcpy_P(public_buf_m, PSTR(machine_menu.wifiName)); + strcat_P(public_buf_m, PSTR((const char *)uiCfg.wifi_name)); + lv_screen_menu_item_1_edit(scr, public_buf_m, PARA_UI_POS_X, PARA_UI_POS_Y * 2, event_handler, ID_WIFI_NAME, 1, machine_menu.wifiEdit); + + strcpy_P(public_buf_m, PSTR(machine_menu.wifiPassWord)); + strcat_P(public_buf_m, PSTR((const char *)uiCfg.wifi_key)); + lv_screen_menu_item_1_edit(scr, public_buf_m, PARA_UI_POS_X, PARA_UI_POS_Y * 3, event_handler, ID_WIFI_PASSWORD, 2, machine_menu.wifiEdit); + + btnCloudState = lv_screen_menu_item_onoff(scr, machine_menu.wifiCloud, PARA_UI_POS_X, PARA_UI_POS_Y * 4, event_handler, ID_WIFI_CLOUD, 3, gCfgItems.cloud_enable); + lv_screen_menu_item_turn_page(scr, machine_menu.wifiConfig, event_handler, ID_WIFI_CONFIG); + lv_screen_menu_item_return(scr, event_handler, ID_WIFI_RETURN); +} + +void lv_clear_wifi_settings() { + #if HAS_ROTARY_ENCODER + if (gCfgItems.encoder_enable) lv_group_remove_all_objs(g); + #endif + lv_obj_del(scr); +} + +#endif // MKS_WIFI_MODULE +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.h new file mode 100644 index 0000000..c0d6e0c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_settings.h @@ -0,0 +1,36 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +#define WIFI_AP_TEXT "AP" +#define WIFI_STA_TEXT "STA" + +extern void lv_draw_wifi_settings(void); +extern void lv_clear_wifi_settings(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.cpp b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.cpp new file mode 100644 index 0000000..7428d36 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.cpp @@ -0,0 +1,68 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include <lv_conf.h> +#include "tft_lvgl_configuration.h" + +#if ENABLED(MKS_WIFI_MODULE) + +#include "draw_ui.h" + +static lv_obj_t *scr; + +TIPS_TYPE wifi_tips_type; +TIPS_DISP tips_disp; +tips_menu_def tips_menu; + +void lv_draw_wifi_tips(void) { + static lv_obj_t *text_tips,*wifi_name; + + scr = lv_screen_create(WIFI_TIPS_UI, ""); + + wifi_name = lv_label_create(scr, (const char *)wifi_list.wifiName[wifi_list.nameIndex]); + lv_obj_align(wifi_name, nullptr, LV_ALIGN_CENTER, 0, -20); + + text_tips = lv_label_create_empty(scr); + if (wifi_tips_type == TIPS_TYPE_JOINING) { + lv_label_set_text(text_tips, tips_menu.joining); + lv_obj_align(text_tips, nullptr, LV_ALIGN_CENTER, 0, -60); + } + else if (wifi_tips_type == TIPS_TYPE_TAILED_JOIN) { + lv_label_set_text(text_tips, tips_menu.failedJoin); + lv_obj_align(text_tips, nullptr, LV_ALIGN_CENTER, 0, -60); + } + else if (wifi_tips_type == TIPS_TYPE_WIFI_CONECTED) { + lv_label_set_text(text_tips, tips_menu.wifiConected); + lv_obj_align(text_tips, nullptr, LV_ALIGN_CENTER, 0, -60); + } + + tips_disp.timer = TIPS_TIMER_START; + tips_disp.timer_count = 0; +} + +void lv_clear_wifi_tips() { lv_obj_del(scr); } + +#endif // MKS_WIFI_MODULE +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.h b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.h new file mode 100644 index 0000000..4f81f00 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/draw_wifi_tips.h @@ -0,0 +1,51 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + + +extern void lv_draw_wifi_tips(void); +extern void lv_clear_wifi_tips(); + +typedef enum { + TIPS_TYPE_JOINING, + TIPS_TYPE_TAILED_JOIN, + TIPS_TYPE_WIFI_CONECTED +} TIPS_TYPE; +extern TIPS_TYPE wifi_tips_type; + +typedef struct { + unsigned char timer; + unsigned int timer_count; +} TIPS_DISP; +extern TIPS_DISP tips_disp; + +#define TIPS_TIMER_START 1 +#define TIPS_TIMER_STOP 0 + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif + diff --git a/Marlin/src/lcd/extui/lib/mks_ui/gb2312_puhui16.cpp b/Marlin/src/lcd/extui/lib/mks_ui/gb2312_puhui16.cpp new file mode 100644 index 0000000..f3585cc --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/gb2312_puhui16.cpp @@ -0,0 +1,105 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "pic_manager.h" +#include <lvgl.h> + +#include "../../../../inc/MarlinConfig.h" + +#if HAS_SPI_FLASH_FONT + +typedef struct { + uint16_t min; + uint16_t max; + uint8_t bpp; + uint8_t reserved[3]; +} x_header_t; + +typedef struct { + uint32_t pos; +} x_table_t; + +typedef struct { + uint8_t adv_w; + uint8_t box_w; +} glyph_dsc_t; + +static x_header_t __g_xbf_hd = { .min = 0, .max = 0, .bpp = 0 }; +static uint8_t __g_font_buf[63]; + +static uint8_t *__user_font_getdata(int offset, int size) { + get_spi_flash_data((char *)__g_font_buf, offset, size); + return __g_font_buf; +} + +static const uint8_t * __user_font_get_bitmap(const lv_font_t * font, uint32_t unicode_letter) { + if (__g_xbf_hd.max == 0) { + uint8_t *p = __user_font_getdata(0, sizeof(x_header_t)); + memcpy(&__g_xbf_hd, p, sizeof(x_header_t)); + } + if (unicode_letter > __g_xbf_hd.max || unicode_letter < __g_xbf_hd.min) + return nullptr; + uint32_t unicode_offset = sizeof(x_header_t) + (unicode_letter - __g_xbf_hd.min) * 4; + uint32_t *p_pos = (uint32_t *)__user_font_getdata(unicode_offset, 4); + if (p_pos[0] != 0) { + uint32_t pos = p_pos[0]; + __user_font_getdata(pos, 2); + return __user_font_getdata(pos + 2, sizeof(__g_font_buf)); + } + return nullptr; +} + +static bool __user_font_get_glyph_dsc(const lv_font_t * font, lv_font_glyph_dsc_t * dsc_out, uint32_t unicode_letter, uint32_t unicode_letter_next) { + if (__g_xbf_hd.max == 0) { + uint8_t *p = __user_font_getdata(0, sizeof(x_header_t)); + memcpy(&__g_xbf_hd, p, sizeof(x_header_t)); + } + if (unicode_letter > __g_xbf_hd.max || unicode_letter < __g_xbf_hd.min) + return false; + uint32_t unicode_offset = sizeof(x_header_t) + (unicode_letter - __g_xbf_hd.min) * 4; + uint32_t *p_pos = (uint32_t *)__user_font_getdata(unicode_offset, 4); + if (p_pos[0] != 0) { + glyph_dsc_t * gdsc = (glyph_dsc_t*)__user_font_getdata(p_pos[0], 2); + dsc_out->adv_w = gdsc->adv_w; + dsc_out->box_h = font->line_height; + dsc_out->box_w = gdsc->box_w; + dsc_out->ofs_x = 0; + dsc_out->ofs_y = 0; + dsc_out->bpp = __g_xbf_hd.bpp; + return true; + } + return false; +} + +lv_font_t gb2312_puhui32; +void init_gb2312_font() { + gb2312_puhui32.get_glyph_bitmap = __user_font_get_bitmap; + gb2312_puhui32.get_glyph_dsc = __user_font_get_glyph_dsc; + gb2312_puhui32.line_height = 21; + gb2312_puhui32.base_line = 0; +} + +#endif // HAS_SPI_FLASH_FONT +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/irq_overrid.cpp b/Marlin/src/lcd/extui/lib/mks_ui/irq_overrid.cpp new file mode 100644 index 0000000..a26116a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/irq_overrid.cpp @@ -0,0 +1,63 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "tft_lvgl_configuration.h" + +#ifdef __STM32F1__ + +#if ENABLED(MKS_WIFI_MODULE) + + #include "draw_ui.h" + #include "wifiSerial.h" + + #include <libmaple/libmaple.h> + #include <libmaple/gpio.h> + #include <libmaple/timer.h> + #include <libmaple/usart.h> + #include <libmaple/ring_buffer.h> + + #include "../../../../inc/MarlinConfig.h" + + #ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ + #endif + + #define WIFI_IO1_SET() WRITE(WIFI_IO1_PIN, HIGH); + #define WIFI_IO1_RESET() WRITE(WIFI_IO1_PIN, LOW); + + void __irq_usart1(void) { + if ((USART1_BASE->CR1 & USART_CR1_RXNEIE) && (USART1_BASE->SR & USART_SR_RXNE)) + WRITE(WIFI_IO1_PIN, HIGH); + + WIFISERIAL.wifi_usart_irq(USART1_BASE); + } + + #ifdef __cplusplus + } /* C-declarations for C++ */ + #endif + +#endif // MKS_WIFI_MODULE +#endif // __STM32F1__ +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp new file mode 100644 index 0000000..4a6a5ce --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.cpp @@ -0,0 +1,655 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "SPI_TFT.h" + +#include "tft_lvgl_configuration.h" +#include "draw_ready_print.h" +#include "mks_hardware_test.h" +#include "draw_ui.h" +#include "pic_manager.h" +#include <lvgl.h> + +#include "../../../../MarlinCore.h" +#include "../../../../module/temperature.h" +#include "../../../../sd/cardreader.h" + +bool pw_det_sta, pw_off_sta, mt_det_sta, mt_det3_sta; +#if PIN_EXISTS(MT_DET_2) + bool mt_det2_sta; +#endif +bool endstopx1_sta, endstopx2_sta, endstopy1_sta, endstopy2_sta, endstopz1_sta, endstopz2_sta; +void test_gpio_readlevel_L() { + #if ENABLED(MKS_TEST) + volatile uint32_t itest; + WRITE(WIFI_IO0_PIN, HIGH); + itest = 10000; + while (itest--); + pw_det_sta = !READ(MKS_TEST_POWER_LOSS_PIN); + pw_off_sta = !READ(MKS_TEST_PS_ON_PIN); + mt_det_sta = !READ(MT_DET_1_PIN); + #if PIN_EXISTS(MT_DET_2) + mt_det2_sta = !READ(MT_DET_2_PIN); + #endif + endstopx1_sta = !READ(X_MIN_PIN); + endstopy1_sta = !READ(Y_MIN_PIN); + endstopz1_sta = !READ(Z_MIN_PIN); + endstopz2_sta = !READ(Z_MAX_PIN); + #endif +} + +void test_gpio_readlevel_H() { + #if ENABLED(MKS_TEST) + volatile uint32_t itest; + WRITE(WIFI_IO0_PIN, LOW); + itest = 10000; + while (itest--); + pw_det_sta = READ(MKS_TEST_POWER_LOSS_PIN); + pw_off_sta = READ(MKS_TEST_PS_ON_PIN); + mt_det_sta = READ(MT_DET_1_PIN); + #if PIN_EXISTS(MT_DET_2) + mt_det2_sta = READ(MT_DET_2_PIN); + #endif + endstopx1_sta = READ(X_MIN_PIN); + endstopy1_sta = READ(Y_MIN_PIN); + endstopz1_sta = READ(Z_MIN_PIN); + endstopz2_sta = READ(Z_MAX_PIN); + #endif +} + +void init_test_gpio() { + #ifdef MKS_TEST + SET_INPUT_PULLUP(X_MIN_PIN); + SET_INPUT_PULLUP(Y_MIN_PIN); + SET_INPUT_PULLUP(Z_MIN_PIN); + SET_INPUT_PULLUP(Z_MAX_PIN); + + SET_OUTPUT(WIFI_IO0_PIN); + + SET_INPUT_PULLUP(MT_DET_1_PIN); + #if PIN_EXISTS(MT_DET_2) + SET_INPUT_PULLUP(MT_DET_2_PIN); + #endif + + SET_INPUT_PULLUP(MKS_TEST_POWER_LOSS_PIN); + SET_INPUT_PULLUP(MKS_TEST_PS_ON_PIN); + + SET_INPUT_PULLUP(SERVO0_PIN); + + SET_OUTPUT(X_ENABLE_PIN); + SET_OUTPUT(Y_ENABLE_PIN); + SET_OUTPUT(Z_ENABLE_PIN); + SET_OUTPUT(E0_ENABLE_PIN); + #if !MB(MKS_ROBIN_E3P) + SET_OUTPUT(E1_ENABLE_PIN); + #endif + + WRITE(X_ENABLE_PIN, LOW); + WRITE(Y_ENABLE_PIN, LOW); + WRITE(Z_ENABLE_PIN, LOW); + WRITE(E0_ENABLE_PIN, LOW); + #if !MB(MKS_ROBIN_E3P) + WRITE(E1_ENABLE_PIN, LOW); + #endif + + #if MB(MKS_ROBIN_E3P) + SET_INPUT_PULLUP(PA1); + SET_INPUT_PULLUP(PA3); + SET_INPUT_PULLUP(PC2); + SET_INPUT_PULLUP(PD8); + SET_INPUT_PULLUP(PE5); + SET_INPUT_PULLUP(PE6); + SET_INPUT_PULLUP(PE7); + #endif + #endif +} + +void mks_test_beeper() { + #ifdef MKS_TEST + WRITE(BEEPER_PIN, HIGH); + delay(100); + WRITE(BEEPER_PIN, LOW); + delay(100); + #endif +} + +void mks_gpio_test() { + #if ENABLED(MKS_TEST) + init_test_gpio(); + + test_gpio_readlevel_L(); + test_gpio_readlevel_H(); + test_gpio_readlevel_L(); + if ((pw_det_sta == true) + && (pw_off_sta == true) + && (mt_det_sta == true) + #if PIN_EXISTS(MT_DET_2) + && (mt_det2_sta == true) + #endif + #if MB(MKS_ROBIN_E3P) + && (READ(PA1) == false) + && (READ(PA3) == false) + && (READ(PC2) == false) + && (READ(PD8) == false) + && (READ(PE5) == false) + && (READ(PE6) == false) + && (READ(PE7) == false) + #endif + ) + disp_det_ok(); + else + disp_det_error(); + + if ( (endstopx1_sta == true) + && (endstopy1_sta == true) + && (endstopz1_sta == true) + && (endstopz2_sta == true) + ) + disp_Limit_ok(); + else + disp_Limit_error(); + #endif + + if (uiCfg.tmc_connect_state) disp_tmc_ok(); + else disp_tmc_error(); +} + +void mks_hardware_test() { + #if ENABLED(MKS_TEST) + if (millis() % 1000 < 500) { + WRITE(X_DIR_PIN, LOW); + WRITE(Y_DIR_PIN, LOW); + WRITE(Z_DIR_PIN, LOW); + WRITE(E0_DIR_PIN, LOW); + #if !MB(MKS_ROBIN_E3P) + WRITE(E1_DIR_PIN, LOW); + #endif + thermalManager.fan_speed[0] = 255; + #if PIN_EXISTS(FAN1) + thermalManager.fan_speed[1] = 255; + #endif + #if !MB(MKS_ROBIN_E3P) + WRITE(HEATER_1_PIN, HIGH); // HE1 + #endif + WRITE(HEATER_0_PIN, HIGH); // HE0 + WRITE(HEATER_BED_PIN, HIGH); // HOT-BED + } + else { + WRITE(X_DIR_PIN, HIGH); + WRITE(Y_DIR_PIN, HIGH); + WRITE(Z_DIR_PIN, HIGH); + WRITE(E0_DIR_PIN, HIGH); + #if !MB(MKS_ROBIN_E3P) + WRITE(E1_DIR_PIN, HIGH); + #endif + thermalManager.fan_speed[0] = 0; + #if PIN_EXISTS(FAN1) + thermalManager.fan_speed[1] = 0; + #endif + #if !MB(MKS_ROBIN_E3P) + WRITE(HEATER_1_PIN, LOW); // HE1 + #endif + WRITE(HEATER_0_PIN, LOW); // HE0 + WRITE(HEATER_BED_PIN, LOW); // HOT-BED + } + + if ( (endstopx1_sta == 1) && (endstopx2_sta == 1) + && (endstopy1_sta == 1) && (endstopy2_sta == 1) + && (endstopz1_sta == 1) && (endstopz2_sta == 1) + ) { + // nothing here + } + else { + } + + if (disp_state == PRINT_READY_UI) mks_disp_test(); + + #endif +} + +static const uint16_t ASCII_Table_16x24[] PROGMEM = { + // Space ' ' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '!' + 0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0000, 0x0000, + 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '"' + 0x0000, 0x0000, 0x00CC, 0x00CC, 0x00CC, 0x00CC, 0x00CC, 0x00CC, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '#' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0C60, 0x0C60, + 0x0C60, 0x0630, 0x0630, 0x1FFE, 0x1FFE, 0x0630, 0x0738, 0x0318, + 0x1FFE, 0x1FFE, 0x0318, 0x0318, 0x018C, 0x018C, 0x018C, 0x0000, + // '$' + 0x0000, 0x0080, 0x03E0, 0x0FF8, 0x0E9C, 0x1C8C, 0x188C, 0x008C, + 0x0098, 0x01F8, 0x07E0, 0x0E80, 0x1C80, 0x188C, 0x188C, 0x189C, + 0x0CB8, 0x0FF0, 0x03E0, 0x0080, 0x0080, 0x0000, 0x0000, 0x0000, + // '%' + 0x0000, 0x0000, 0x0000, 0x180E, 0x0C1B, 0x0C11, 0x0611, 0x0611, + 0x0311, 0x0311, 0x019B, 0x018E, 0x38C0, 0x6CC0, 0x4460, 0x4460, + 0x4430, 0x4430, 0x4418, 0x6C18, 0x380C, 0x0000, 0x0000, 0x0000, + // '&' + 0x0000, 0x01E0, 0x03F0, 0x0738, 0x0618, 0x0618, 0x0330, 0x01F0, + 0x00F0, 0x00F8, 0x319C, 0x330E, 0x1E06, 0x1C06, 0x1C06, 0x3F06, + 0x73FC, 0x21F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // "'" + 0x0000, 0x0000, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '(' + 0x0000, 0x0200, 0x0300, 0x0180, 0x00C0, 0x00C0, 0x0060, 0x0060, + 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0060, 0x0060, 0x00C0, 0x00C0, 0x0180, 0x0300, 0x0200, 0x0000, + // ')' + 0x0000, 0x0020, 0x0060, 0x00C0, 0x0180, 0x0180, 0x0300, 0x0300, + 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, + 0x0300, 0x0300, 0x0180, 0x0180, 0x00C0, 0x0060, 0x0020, 0x0000, + // '*' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00C0, 0x00C0, + 0x06D8, 0x07F8, 0x01E0, 0x0330, 0x0738, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '+' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0180, 0x3FFC, 0x3FFC, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // ',' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0180, 0x0180, 0x0100, 0x0100, 0x0080, 0x0000, 0x0000, + // '-' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x07E0, 0x07E0, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '.' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '/' + 0x0000, 0x0C00, 0x0C00, 0x0600, 0x0600, 0x0600, 0x0300, 0x0300, + 0x0300, 0x0380, 0x0180, 0x0180, 0x0180, 0x00C0, 0x00C0, 0x00C0, + 0x0060, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '0' + 0x0000, 0x03E0, 0x07F0, 0x0E38, 0x0C18, 0x180C, 0x180C, 0x180C, + 0x180C, 0x180C, 0x180C, 0x180C, 0x180C, 0x180C, 0x0C18, 0x0E38, + 0x07F0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '1' + 0x0000, 0x0100, 0x0180, 0x01C0, 0x01F0, 0x0198, 0x0188, 0x0180, + 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '2' + 0x0000, 0x03E0, 0x0FF8, 0x0C18, 0x180C, 0x180C, 0x1800, 0x1800, + 0x0C00, 0x0600, 0x0300, 0x0180, 0x00C0, 0x0060, 0x0030, 0x0018, + 0x1FFC, 0x1FFC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '3' + 0x0000, 0x01E0, 0x07F8, 0x0E18, 0x0C0C, 0x0C0C, 0x0C00, 0x0600, + 0x03C0, 0x07C0, 0x0C00, 0x1800, 0x1800, 0x180C, 0x180C, 0x0C18, + 0x07F8, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '4' + 0x0000, 0x0C00, 0x0E00, 0x0F00, 0x0F00, 0x0D80, 0x0CC0, 0x0C60, + 0x0C60, 0x0C30, 0x0C18, 0x0C0C, 0x3FFC, 0x3FFC, 0x0C00, 0x0C00, + 0x0C00, 0x0C00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '5' + 0x0000, 0x0FF8, 0x0FF8, 0x0018, 0x0018, 0x000C, 0x03EC, 0x07FC, + 0x0E1C, 0x1C00, 0x1800, 0x1800, 0x1800, 0x180C, 0x0C1C, 0x0E18, + 0x07F8, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '6' + 0x0000, 0x07C0, 0x0FF0, 0x1C38, 0x1818, 0x0018, 0x000C, 0x03CC, + 0x0FEC, 0x0E3C, 0x1C1C, 0x180C, 0x180C, 0x180C, 0x1C18, 0x0E38, + 0x07F0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '7' + 0x0000, 0x1FFC, 0x1FFC, 0x0C00, 0x0600, 0x0600, 0x0300, 0x0380, + 0x0180, 0x01C0, 0x00C0, 0x00E0, 0x0060, 0x0060, 0x0070, 0x0030, + 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '8' + 0x0000, 0x03E0, 0x07F0, 0x0E38, 0x0C18, 0x0C18, 0x0C18, 0x0638, + 0x07F0, 0x07F0, 0x0C18, 0x180C, 0x180C, 0x180C, 0x180C, 0x0C38, + 0x0FF8, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '9' + 0x0000, 0x03E0, 0x07F0, 0x0E38, 0x0C1C, 0x180C, 0x180C, 0x180C, + 0x1C1C, 0x1E38, 0x1BF8, 0x19E0, 0x1800, 0x0C00, 0x0C00, 0x0E1C, + 0x07F8, 0x01F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // ':' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0180, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // ';' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0180, 0x0180, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0180, 0x0180, 0x0100, 0x0100, 0x0080, 0x0000, 0x0000, 0x0000, + // '<' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1000, 0x1C00, 0x0F80, 0x03E0, 0x00F8, 0x0018, 0x00F8, 0x03E0, + 0x0F80, 0x1C00, 0x1000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '=' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x1FF8, 0x0000, 0x0000, 0x0000, 0x1FF8, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '>' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0008, 0x0038, 0x01F0, 0x07C0, 0x1F00, 0x1800, 0x1F00, 0x07C0, + 0x01F0, 0x0038, 0x0008, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '?' + 0x0000, 0x03E0, 0x0FF8, 0x0C18, 0x180C, 0x180C, 0x1800, 0x0C00, + 0x0600, 0x0300, 0x0180, 0x00C0, 0x00C0, 0x00C0, 0x0000, 0x0000, + 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '@' + 0x0000, 0x0000, 0x07E0, 0x1818, 0x2004, 0x29C2, 0x4A22, 0x4411, + 0x4409, 0x4409, 0x4409, 0x2209, 0x1311, 0x0CE2, 0x4002, 0x2004, + 0x1818, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'A' + 0x0000, 0x0380, 0x0380, 0x06C0, 0x06C0, 0x06C0, 0x0C60, 0x0C60, + 0x1830, 0x1830, 0x1830, 0x3FF8, 0x3FF8, 0x701C, 0x600C, 0x600C, + 0xC006, 0xC006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'B' + 0x0000, 0x03FC, 0x0FFC, 0x0C0C, 0x180C, 0x180C, 0x180C, 0x0C0C, + 0x07FC, 0x0FFC, 0x180C, 0x300C, 0x300C, 0x300C, 0x300C, 0x180C, + 0x1FFC, 0x07FC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'C' + 0x0000, 0x07C0, 0x1FF0, 0x3838, 0x301C, 0x700C, 0x6006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x6006, 0x700C, 0x301C, + 0x1FF0, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'D' + 0x0000, 0x03FE, 0x0FFE, 0x0E06, 0x1806, 0x1806, 0x3006, 0x3006, + 0x3006, 0x3006, 0x3006, 0x3006, 0x3006, 0x1806, 0x1806, 0x0E06, + 0x0FFE, 0x03FE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'E' + 0x0000, 0x3FFC, 0x3FFC, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, + 0x1FFC, 0x1FFC, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, + 0x3FFC, 0x3FFC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'F' + 0x0000, 0x3FF8, 0x3FF8, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x1FF8, 0x1FF8, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'G' + 0x0000, 0x0FE0, 0x3FF8, 0x783C, 0x600E, 0xE006, 0xC007, 0x0003, + 0x0003, 0xFE03, 0xFE03, 0xC003, 0xC007, 0xC006, 0xC00E, 0xF03C, + 0x3FF8, 0x0FE0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'H' + 0x0000, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, + 0x3FFC, 0x3FFC, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, + 0x300C, 0x300C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'I' + 0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'J' + 0x0000, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, + 0x0600, 0x0600, 0x0600, 0x0600, 0x0600, 0x0618, 0x0618, 0x0738, + 0x03F0, 0x01E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'K' + 0x0000, 0x3006, 0x1806, 0x0C06, 0x0606, 0x0306, 0x0186, 0x00C6, + 0x0066, 0x0076, 0x00DE, 0x018E, 0x0306, 0x0606, 0x0C06, 0x1806, + 0x3006, 0x6006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'L' + 0x0000, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, + 0x1FF8, 0x1FF8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'M' + 0x0000, 0xE00E, 0xF01E, 0xF01E, 0xF01E, 0xD836, 0xD836, 0xD836, + 0xD836, 0xCC66, 0xCC66, 0xCC66, 0xC6C6, 0xC6C6, 0xC6C6, 0xC6C6, + 0xC386, 0xC386, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'N' + 0x0000, 0x300C, 0x301C, 0x303C, 0x303C, 0x306C, 0x306C, 0x30CC, + 0x30CC, 0x318C, 0x330C, 0x330C, 0x360C, 0x360C, 0x3C0C, 0x3C0C, + 0x380C, 0x300C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'O' + 0x0000, 0x07E0, 0x1FF8, 0x381C, 0x700E, 0x6006, 0xC003, 0xC003, + 0xC003, 0xC003, 0xC003, 0xC003, 0xC003, 0x6006, 0x700E, 0x381C, + 0x1FF8, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'P' + 0x0000, 0x0FFC, 0x1FFC, 0x380C, 0x300C, 0x300C, 0x300C, 0x300C, + 0x180C, 0x1FFC, 0x07FC, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, + 0x000C, 0x000C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'Q' + 0x0000, 0x07E0, 0x1FF8, 0x381C, 0x700E, 0x6006, 0xE003, 0xC003, + 0xC003, 0xC003, 0xC003, 0xC003, 0xE007, 0x6306, 0x3F0E, 0x3C1C, + 0x3FF8, 0xF7E0, 0xC000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'R' + 0x0000, 0x0FFE, 0x1FFE, 0x3806, 0x3006, 0x3006, 0x3006, 0x3806, + 0x1FFE, 0x07FE, 0x0306, 0x0606, 0x0C06, 0x1806, 0x1806, 0x3006, + 0x3006, 0x6006, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'S' + 0x0000, 0x03E0, 0x0FF8, 0x0C1C, 0x180C, 0x180C, 0x000C, 0x001C, + 0x03F8, 0x0FE0, 0x1E00, 0x3800, 0x3006, 0x3006, 0x300E, 0x1C1C, + 0x0FF8, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'T' + 0x0000, 0x7FFE, 0x7FFE, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'U' + 0x0000, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, + 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x300C, 0x1818, + 0x1FF8, 0x07E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'V' + 0x0000, 0x6003, 0x3006, 0x3006, 0x3006, 0x180C, 0x180C, 0x180C, + 0x0C18, 0x0C18, 0x0E38, 0x0630, 0x0630, 0x0770, 0x0360, 0x0360, + 0x01C0, 0x01C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'W' + 0x0000, 0x6003, 0x61C3, 0x61C3, 0x61C3, 0x3366, 0x3366, 0x3366, + 0x3366, 0x3366, 0x3366, 0x1B6C, 0x1B6C, 0x1B6C, 0x1A2C, 0x1E3C, + 0x0E38, 0x0E38, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'X' + 0x0000, 0xE00F, 0x700C, 0x3018, 0x1830, 0x0C70, 0x0E60, 0x07C0, + 0x0380, 0x0380, 0x03C0, 0x06E0, 0x0C70, 0x1C30, 0x1818, 0x300C, + 0x600E, 0xE007, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'Y' + 0x0000, 0xC003, 0x6006, 0x300C, 0x381C, 0x1838, 0x0C30, 0x0660, + 0x07E0, 0x03C0, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'Z' + 0x0000, 0x7FFC, 0x7FFC, 0x6000, 0x3000, 0x1800, 0x0C00, 0x0600, + 0x0300, 0x0180, 0x00C0, 0x0060, 0x0030, 0x0018, 0x000C, 0x0006, + 0x7FFE, 0x7FFE, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '[' + 0x0000, 0x03E0, 0x03E0, 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, + 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, + 0x0060, 0x0060, 0x0060, 0x0060, 0x0060, 0x03E0, 0x03E0, 0x0000, + // '\' + 0x0000, 0x0030, 0x0030, 0x0060, 0x0060, 0x0060, 0x00C0, 0x00C0, + 0x00C0, 0x01C0, 0x0180, 0x0180, 0x0180, 0x0300, 0x0300, 0x0300, + 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // ']' + 0x0000, 0x03E0, 0x03E0, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, + 0x0300, 0x0300, 0x0300, 0x0300, 0x0300, 0x03E0, 0x03E0, 0x0000, + // '^' + 0x0000, 0x0000, 0x01C0, 0x01C0, 0x0360, 0x0360, 0x0360, 0x0630, + 0x0630, 0x0C18, 0x0C18, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '_' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // ''' + 0x0000, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'a' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03F0, 0x07F8, + 0x0C1C, 0x0C0C, 0x0F00, 0x0FF0, 0x0CF8, 0x0C0C, 0x0C0C, 0x0F1C, + 0x0FF8, 0x18F0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'b' + 0x0000, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x03D8, 0x0FF8, + 0x0C38, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x0C38, + 0x0FF8, 0x03D8, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'c' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03C0, 0x07F0, + 0x0E30, 0x0C18, 0x0018, 0x0018, 0x0018, 0x0018, 0x0C18, 0x0E30, + 0x07F0, 0x03C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'd' + 0x0000, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x1BC0, 0x1FF0, + 0x1C30, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1C30, + 0x1FF0, 0x1BC0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'e' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03C0, 0x0FF0, + 0x0C30, 0x1818, 0x1FF8, 0x1FF8, 0x0018, 0x0018, 0x1838, 0x1C30, + 0x0FF0, 0x07C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'f' + 0x0000, 0x0F80, 0x0FC0, 0x00C0, 0x00C0, 0x00C0, 0x07F0, 0x07F0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'g' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0DE0, 0x0FF8, + 0x0E18, 0x0C0C, 0x0C0C, 0x0C0C, 0x0C0C, 0x0C0C, 0x0C0C, 0x0E18, + 0x0FF8, 0x0DE0, 0x0C00, 0x0C0C, 0x061C, 0x07F8, 0x01F0, 0x0000, + // 'h' + 0x0000, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x07D8, 0x0FF8, + 0x1C38, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, + 0x1818, 0x1818, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'i' + 0x0000, 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'j' + 0x0000, 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00F8, 0x0078, 0x0000, + // 'k' + 0x0000, 0x000C, 0x000C, 0x000C, 0x000C, 0x000C, 0x0C0C, 0x060C, + 0x030C, 0x018C, 0x00CC, 0x006C, 0x00FC, 0x019C, 0x038C, 0x030C, + 0x060C, 0x0C0C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'l' + 0x0000, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'm' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3C7C, 0x7EFF, + 0xE3C7, 0xC183, 0xC183, 0xC183, 0xC183, 0xC183, 0xC183, 0xC183, + 0xC183, 0xC183, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'n' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0798, 0x0FF8, + 0x1C38, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, + 0x1818, 0x1818, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'o' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03C0, 0x0FF0, + 0x0C30, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x0C30, + 0x0FF0, 0x03C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'p' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03D8, 0x0FF8, + 0x0C38, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x0C38, + 0x0FF8, 0x03D8, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0000, + // 'q' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1BC0, 0x1FF0, + 0x1C30, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1C30, + 0x1FF0, 0x1BC0, 0x1800, 0x1800, 0x1800, 0x1800, 0x1800, 0x0000, + // 'r' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x07B0, 0x03F0, + 0x0070, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, + 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 's' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03E0, 0x03F0, + 0x0E38, 0x0C18, 0x0038, 0x03F0, 0x07C0, 0x0C00, 0x0C18, 0x0E38, + 0x07F0, 0x03E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 't' + 0x0000, 0x0000, 0x0080, 0x00C0, 0x00C0, 0x00C0, 0x07F0, 0x07F0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x07C0, 0x0780, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'u' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1818, 0x1818, + 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1818, 0x1C38, + 0x1FF0, 0x19E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'v' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x180C, 0x0C18, + 0x0C18, 0x0C18, 0x0630, 0x0630, 0x0630, 0x0360, 0x0360, 0x0360, + 0x01C0, 0x01C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'w' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x41C1, 0x41C1, + 0x61C3, 0x6363, 0x6363, 0x6363, 0x3636, 0x3636, 0x3636, 0x1C1C, + 0x1C1C, 0x1C1C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'x' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x381C, 0x1C38, + 0x0C30, 0x0660, 0x0360, 0x0360, 0x0360, 0x0360, 0x0660, 0x0C30, + 0x1C38, 0x381C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // 'y' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x3018, 0x1830, + 0x1830, 0x1870, 0x0C60, 0x0C60, 0x0CE0, 0x06C0, 0x06C0, 0x0380, + 0x0380, 0x0380, 0x0180, 0x0180, 0x01C0, 0x00F0, 0x0070, 0x0000, + // 'z' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1FFC, 0x1FFC, + 0x0C00, 0x0600, 0x0300, 0x0180, 0x00C0, 0x0060, 0x0030, 0x0018, + 0x1FFC, 0x1FFC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + // '{' + 0x0000, 0x0300, 0x0180, 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x00C0, + 0x00C0, 0x0060, 0x0060, 0x0030, 0x0060, 0x0040, 0x00C0, 0x00C0, + 0x00C0, 0x00C0, 0x00C0, 0x00C0, 0x0180, 0x0300, 0x0000, 0x0000, + // '|' + 0x0000, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0180, 0x0000, + // '}' + 0x0000, 0x0060, 0x00C0, 0x01C0, 0x0180, 0x0180, 0x0180, 0x0180, + 0x0180, 0x0300, 0x0300, 0x0600, 0x0300, 0x0100, 0x0180, 0x0180, + 0x0180, 0x0180, 0x0180, 0x0180, 0x00C0, 0x0060, 0x0000, 0x0000, + // '~' + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x10F0, 0x1FF8, 0x0F08, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, +}; + +void disp_char_1624(uint16_t x, uint16_t y, uint8_t c, uint16_t charColor, uint16_t bkColor) { + for (uint16_t i = 0; i < 24; i++) { + const uint16_t tmp_char = pgm_read_word(&ASCII_Table_16x24[((c - 0x20) * 24) + i]); + for (uint16_t j = 0; j < 16; j++) + SPI_TFT.SetPoint(x + j, y + i, ((tmp_char >> j) & 0x01) ? charColor : bkColor); + } +} + +void disp_string(uint16_t x, uint16_t y, const char * string, uint16_t charColor, uint16_t bkColor) { + while (*string != '\0') { + disp_char_1624(x, y, *string, charColor, bkColor); + string++; + x += 16; + } +} + +void disp_assets_update() { + SPI_TFT.LCD_clear(0x0000); + disp_string(100, 140, "Assets Updating...", 0xFFFF, 0x0000); +} + +void disp_assets_update_progress(const char *msg) { + char buf[30]; + memset(buf, ' ', COUNT(buf)); + strncpy(buf, msg, strlen(msg)); + buf[COUNT(buf)-1] = '\0'; + disp_string(100, 165, buf, 0xFFFF, 0x0000); +} + +uint8_t mks_test_flag = 0; +const char *MKSTestPath = "MKS_TEST"; + +#if ENABLED(SDSUPPORT) + void mks_test_get() { + SdFile dir, root = card.getroot(); + if (dir.open(&root, MKSTestPath, O_RDONLY)) + mks_test_flag = 0x1E; + } +#endif + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.h b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.h new file mode 100644 index 0000000..0e2d809 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/mks_hardware_test.h @@ -0,0 +1,33 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include <lvgl.h> + +void mks_gpio_test(); +void disp_char_1624(uint16_t x, uint16_t y, uint8_t c, uint16_t charColor, uint16_t bkColor); +void disp_string(uint16_t x, uint16_t y, const char * string, uint16_t charColor, uint16_t bkColor); +void mks_hardware_test(); +void disp_assets_update(); +void disp_assets_update_progress(const char *msg); +void mks_test_get(); +extern uint8_t mks_test_flag; diff --git a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp new file mode 100644 index 0000000..51aab0a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.cpp @@ -0,0 +1,622 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "string.h" +#include "draw_ui.h" +#include "pic_manager.h" +#include "draw_ready_print.h" +#include "mks_hardware_test.h" + +#include "SPIFlashStorage.h" +#include "../../../../libs/W25Qxx.h" + +#include "../../../../sd/cardreader.h" +#include "../../../../MarlinCore.h" + +extern uint16_t DeviceCode; + +#if ENABLED(SDSUPPORT) + extern char *createFilename(char * const buffer, const dir_t &p); +#endif + +static const char assets[][LONG_FILENAME_LENGTH] = { + //homing screen + "bmp_zeroAll.bin", + "bmp_zero.bin", + "bmp_zeroX.bin", + "bmp_zeroY.bin", + "bmp_zeroZ.bin", + "bmp_manual_off.bin", + + //tool screen + "bmp_preHeat.bin", + "bmp_extruct.bin", + "bmp_mov.bin", + "bmp_leveling.bin", + "bmp_filamentchange.bin", + "bmp_more.bin", + + //fan screen + "bmp_Add.bin", + "bmp_Dec.bin", + "bmp_speed255.bin", + "bmp_speed127.bin", + "bmp_speed0.bin", + "bmp_speed0.bin", + + "bmp_bed.bin", + "bmp_step1_degree.bin", + "bmp_step5_degree.bin", + "bmp_step10_degree.bin", + + //extrusion screen + "bmp_in.bin", + "bmp_out.bin", + "bmp_extru1.bin", + #if HAS_MULTI_EXTRUDER + "bmp_extru2.bin", + #endif + "bmp_speed_high.bin", + "bmp_speed_slow.bin", + "bmp_speed_normal.bin", + "bmp_step1_mm.bin", + "bmp_step5_mm.bin", + "bmp_step10_mm.bin", + + //select file screen + "bmp_pageUp.bin", + "bmp_pageDown.bin", + "bmp_back.bin", //TODO: why two back buttons? Why not just one? (return / back) + "bmp_dir.bin", + "bmp_file.bin", + + //move motor screen + //TODO: 6 equal icons, just in diffenct rotation... it may be optimized too + "bmp_xAdd.bin", + "bmp_xDec.bin", + "bmp_yAdd.bin", + "bmp_yDec.bin", + "bmp_zAdd.bin", + "bmp_zDec.bin", + "bmp_step_move0_1.bin", + "bmp_step_move1.bin", + "bmp_step_move10.bin", + + //operation screen + "bmp_auto_off.bin", + "bmp_speed.bin", + "bmp_fan.bin", + "bmp_temp.bin", + "bmp_extrude_opr.bin", + "bmp_move_opr.bin", + + //change speed screen + "bmp_step1_percent.bin", + "bmp_step5_percent.bin", + "bmp_step10_percent.bin", + "bmp_extruct_sel.bin", + "bmp_mov_changespeed.bin", + "bmp_mov_sel.bin", + "bmp_speed_extruct.bin", + + //printing screen + "bmp_pause.bin", + "bmp_resume.bin", + "bmp_stop.bin", + "bmp_ext1_state.bin", + #if HAS_MULTI_EXTRUDER + "bmp_ext2_state.bin", + #endif + "bmp_bed_state.bin", + "bmp_fan_state.bin", + "bmp_time_state.bin", + "bmp_zpos_state.bin", + "bmp_operate.bin", + + //manual leval screen (only if disabled auto level) + #if DISABLED(AUTO_BED_LEVELING_BILINEAR) + "bmp_leveling1.bin", + "bmp_leveling2.bin", + "bmp_leveling3.bin", + "bmp_leveling4.bin", + "bmp_leveling5.bin", + #endif + + //lang select screen + #if HAS_LANG_SELECT_SCREEN + "bmp_language.bin", + "bmp_simplified_cn.bin", + "bmp_simplified_cn_sel.bin", + "bmp_traditional_cn.bin", + "bmp_traditional_cn_sel.bin", + "bmp_english.bin", + "bmp_english_sel.bin", + "bmp_russian.bin", + "bmp_russian_sel.bin", + "bmp_spanish.bin", + "bmp_spanish_sel.bin", + "bmp_french.bin", + "bmp_french_sel.bin", + "bmp_italy.bin", + "bmp_italy_sel.bin", + #endif // HAS_LANG_SELECT_SCREEN + + // gcode preview + #if HAS_GCODE_DEFAULT_VIEW_IN_FLASH + "bmp_preview.bin", + #endif + + #if HAS_LOGO_IN_FLASH + "bmp_logo.bin", + #endif + + // settings screen + "bmp_about.bin", + "bmp_eeprom_settings.bin", + "bmp_machine_para.bin", + "bmp_function1.bin", + + //start screen + "bmp_printing.bin", + "bmp_set.bin", + "bmp_tool.bin", + + // base icons + "bmp_arrow.bin", + "bmp_back70x40.bin", + "bmp_value_blank.bin", + "bmp_blank_sel.bin", + "bmp_disable.bin", + "bmp_enable.bin", + "bmp_return.bin", + + #if ENABLED(MKS_WIFI_MODULE) + // wifi screen + "bmp_wifi.bin", + "bmp_cloud.bin", + #endif + + // babystep screen + "bmp_baby_move0_01.bin", + "bmp_baby_move0_05.bin", + "bmp_baby_move0_1.bin", + + // more screen + "bmp_custom1.bin", + "bmp_custom2.bin", + "bmp_custom3.bin", + "bmp_custom4.bin", + "bmp_custom5.bin", + "bmp_custom6.bin", + "bmp_custom7.bin" +}; + +#if HAS_SPI_FLASH_FONT + static char fonts[][LONG_FILENAME_LENGTH] = { "FontUNIGBK.bin" }; +#endif + +uint8_t currentFlashPage = 0; + +uint32_t lv_get_pic_addr(uint8_t *Pname) { + uint8_t Pic_cnt; + uint8_t i, j; + PIC_MSG PIC; + uint32_t tmp_cnt = 0; + uint32_t addr = 0; + + currentFlashPage = 0; + + #if ENABLED(MARLIN_DEV_MODE) + SERIAL_ECHOLNPAIR("Getting picture SPI Flash Address: ", (const char*)Pname); + #endif + + W25QXX.init(SPI_QUARTER_SPEED); + + W25QXX.SPI_FLASH_BufferRead(&Pic_cnt, PIC_COUNTER_ADDR, 1); + if (Pic_cnt == 0xFF) Pic_cnt = 0; + for (i = 0; i < Pic_cnt; i++) { + j = 0; + do { + W25QXX.SPI_FLASH_BufferRead(&PIC.name[j], PIC_NAME_ADDR + tmp_cnt, 1); + tmp_cnt++; + } while (PIC.name[j++] != '\0'); + + if ((strcasecmp((char*)Pname, (char*)PIC.name)) == 0) { + if ((DeviceCode == 0x9488) || (DeviceCode == 0x5761)) + addr = PIC_DATA_ADDR_TFT35 + i * PER_PIC_MAX_SPACE_TFT35; + else + addr = PIC_DATA_ADDR_TFT32 + i * PER_PIC_MAX_SPACE_TFT32; + return addr; + } + } + + return addr; +} + +const char *assetsPath = "assets"; +const char *bakPath = "_assets"; + +void spiFlashErase_PIC() { + volatile uint32_t pic_sectorcnt = 0; + W25QXX.init(SPI_QUARTER_SPEED); + //erase 0x001000 -64K + for (pic_sectorcnt = 0; pic_sectorcnt < (64 - 4) / 4; pic_sectorcnt++) { + watchdog_refresh(); + W25QXX.SPI_FLASH_SectorErase(PICINFOADDR + pic_sectorcnt * 4 * 1024); + } + //erase 64K -- 6M + for (pic_sectorcnt = 0; pic_sectorcnt < (PIC_SIZE_xM * 1024 / 64 - 1); pic_sectorcnt++) { + watchdog_refresh(); + W25QXX.SPI_FLASH_BlockErase((pic_sectorcnt + 1) * 64 * 1024); + } +} + +#if HAS_SPI_FLASH_FONT + void spiFlashErase_FONT() { + volatile uint32_t Font_sectorcnt = 0; + W25QXX.init(SPI_QUARTER_SPEED); + for (Font_sectorcnt = 0; Font_sectorcnt < 32-1; Font_sectorcnt++) { + watchdog_refresh(); + W25QXX.SPI_FLASH_BlockErase(FONTINFOADDR + Font_sectorcnt * 64 * 1024); + } + } +#endif + +uint32_t LogoWrite_Addroffset = 0; + +uint8_t Pic_Logo_Write(uint8_t *LogoName, uint8_t *Logo_Wbuff, uint32_t LogoWriteSize) { + if (LogoWriteSize <= 0) return 0; + + W25QXX.SPI_FLASH_BufferWrite(Logo_Wbuff, PIC_LOGO_ADDR + LogoWrite_Addroffset, LogoWriteSize); + + for (uint32_t i = 0; i < LogoWriteSize; i++) { + uint8_t temp1; + W25QXX.SPI_FLASH_BufferRead(&temp1, PIC_LOGO_ADDR + LogoWrite_Addroffset + i, 1); + if (*(Logo_Wbuff + i) != temp1) return 0; + } + LogoWrite_Addroffset += LogoWriteSize; + const uint32_t logo_maxsize = DeviceCode == 0x9488 || DeviceCode == 0x5761 ? LOGO_MAX_SIZE_TFT35 : LOGO_MAX_SIZE_TFT32; + if (LogoWrite_Addroffset >= logo_maxsize) LogoWrite_Addroffset = 0; + return 1; +} + +uint32_t TitleLogoWrite_Addroffset = 0; +uint8_t Pic_TitleLogo_Write(uint8_t *TitleLogoName, uint8_t *TitleLogo_Wbuff, uint32_t TitleLogoWriteSize) { + if (TitleLogoWriteSize <= 0) + return 0; + if ((DeviceCode == 0x9488) || (DeviceCode == 0x5761)) + W25QXX.SPI_FLASH_BufferWrite(TitleLogo_Wbuff, PIC_ICON_LOGO_ADDR_TFT35 + TitleLogoWrite_Addroffset, TitleLogoWriteSize); + else + W25QXX.SPI_FLASH_BufferWrite(TitleLogo_Wbuff, PIC_ICON_LOGO_ADDR_TFT32 + TitleLogoWrite_Addroffset, TitleLogoWriteSize); + TitleLogoWrite_Addroffset += TitleLogoWriteSize; + if (TitleLogoWrite_Addroffset >= TITLELOGO_MAX_SIZE) + TitleLogoWrite_Addroffset = 0; + return 1; +} + +uint32_t default_view_addroffset_r = 0; +void default_view_Write(uint8_t *default_view__Rbuff, uint32_t default_view_Writesize) { + W25QXX.SPI_FLASH_BufferWrite(default_view__Rbuff, DEFAULT_VIEW_ADDR_TFT35 + default_view_addroffset_r, default_view_Writesize); + default_view_addroffset_r += default_view_Writesize; + if (default_view_addroffset_r >= DEFAULT_VIEW_MAX_SIZE) + default_view_addroffset_r = 0; +} + +uint32_t Pic_Info_Write(uint8_t *P_name, uint32_t P_size) { + uint8_t pic_counter = 0; + uint32_t Pic_SaveAddr; + uint32_t Pic_SizeSaveAddr; + uint32_t Pic_NameSaveAddr; + uint8_t Pname_temp; + uint32_t i, j; + uint32_t name_len = 0; + uint32_t SaveName_len = 0; + union union32 size_tmp; + + W25QXX.SPI_FLASH_BufferRead(&pic_counter, PIC_COUNTER_ADDR, 1); + + if (pic_counter == 0xFF) + pic_counter = 0; + + if ((DeviceCode == 0x9488) || (DeviceCode == 0x5761)) + Pic_SaveAddr = PIC_DATA_ADDR_TFT35 + pic_counter * PER_PIC_MAX_SPACE_TFT35; + else + Pic_SaveAddr = PIC_DATA_ADDR_TFT32 + pic_counter * PER_PIC_MAX_SPACE_TFT32; + + for (j = 0; j < pic_counter; j++) { + do { + W25QXX.SPI_FLASH_BufferRead(&Pname_temp, PIC_NAME_ADDR + SaveName_len, 1); + SaveName_len++; + } while (Pname_temp != '\0'); + } + i = 0; + while ((*(P_name + i) != '\0')) { + i++; + name_len++; + } + + Pic_NameSaveAddr = PIC_NAME_ADDR + SaveName_len; + W25QXX.SPI_FLASH_BufferWrite(P_name, Pic_NameSaveAddr, name_len + 1); + Pic_SizeSaveAddr = PIC_SIZE_ADDR + 4 * pic_counter; + size_tmp.dwords = P_size; + W25QXX.SPI_FLASH_BufferWrite(size_tmp.bytes, Pic_SizeSaveAddr, 4); + + pic_counter++; + W25QXX.SPI_FLASH_SectorErase(PIC_COUNTER_ADDR); + W25QXX.SPI_FLASH_BufferWrite(&pic_counter, PIC_COUNTER_ADDR, 1); + + return Pic_SaveAddr; +} + +#if ENABLED(SDSUPPORT) + + static void dosName2LongName(const char dosName[11], char* longName) { + uint8_t j = 0; + LOOP_L_N(i, 11) { + if (i == 8) longName[j++] = '.'; + if (dosName[i] == '\0' || dosName[i] == ' ') continue; + longName[j++] = dosName[i]; + } + longName[j] = '\0'; + } + + static int8_t arrayFindStr(const char arr[][LONG_FILENAME_LENGTH], uint8_t arraySize, const char* str) { + for (uint8_t a = 0; a < arraySize; a++) { + if (strcasecmp(arr[a], str) == 0) + return a; + } + return -1; + } + + #if ENABLED(MARLIN_DEV_MODE) + static uint32_t totalSizes = 0, totalCompressed = 0; + #endif + + #define ASSET_TYPE_ICON 0 + #define ASSET_TYPE_LOGO 1 + #define ASSET_TYPE_TITLE_LOGO 2 + #define ASSET_TYPE_G_PREVIEW 3 + #define ASSET_TYPE_FONT 4 + static void loadAsset(SdFile &dir, dir_t& entry, const char *fn, int8_t assetType) { + SdFile file; + char dosFilename[FILENAME_LENGTH]; + createFilename(dosFilename, entry); + if (!file.open(&dir, dosFilename, O_READ)) { + #if ENABLED(MARLIN_DEV_MODE) + SERIAL_ECHOLNPAIR("Error opening Asset: ", fn); + #endif + return; + } + + watchdog_refresh(); + disp_assets_update_progress(fn); + + W25QXX.init(SPI_QUARTER_SPEED); + + uint16_t pbr; + uint32_t pfileSize; + uint32_t totalSizeLoaded = 0; + uint32_t Pic_Write_Addr; + pfileSize = file.fileSize(); + totalSizeLoaded += pfileSize; + if (assetType == ASSET_TYPE_LOGO) { + do { + watchdog_refresh(); + pbr = file.read(public_buf, BMP_WRITE_BUF_LEN); + Pic_Logo_Write((uint8_t *)fn, public_buf, pbr); + } while (pbr >= BMP_WRITE_BUF_LEN); + } + else if (assetType == ASSET_TYPE_TITLE_LOGO) { + do { + watchdog_refresh(); + pbr = file.read(public_buf, BMP_WRITE_BUF_LEN); + Pic_TitleLogo_Write((uint8_t *)fn, public_buf, pbr); + } while (pbr >= BMP_WRITE_BUF_LEN); + } + else if (assetType == ASSET_TYPE_G_PREVIEW) { + do { + watchdog_refresh(); + pbr = file.read(public_buf, BMP_WRITE_BUF_LEN); + default_view_Write(public_buf, pbr); + } while (pbr >= BMP_WRITE_BUF_LEN); + } + else if (assetType == ASSET_TYPE_ICON) { + Pic_Write_Addr = Pic_Info_Write((uint8_t *)fn, pfileSize); + SPIFlash.beginWrite(Pic_Write_Addr); + #if HAS_SPI_FLASH_COMPRESSION + do { + watchdog_refresh(); + pbr = file.read(public_buf, SPI_FLASH_PageSize); + TERN_(MARLIN_DEV_MODE, totalSizes += pbr); + SPIFlash.writeData(public_buf, SPI_FLASH_PageSize); + } while (pbr >= SPI_FLASH_PageSize); + #else + do { + pbr = file.read(public_buf, BMP_WRITE_BUF_LEN); + W25QXX.SPI_FLASH_BufferWrite(public_buf, Pic_Write_Addr, pbr); + Pic_Write_Addr += pbr; + } while (pbr >= BMP_WRITE_BUF_LEN); + #endif + #if ENABLED(MARLIN_DEV_MODE) + SERIAL_ECHOLNPAIR("Space used: ", fn, " - ", (SPIFlash.getCurrentPage() + 1) * SPI_FLASH_PageSize / 1024, "KB"); + totalCompressed += (SPIFlash.getCurrentPage() + 1) * SPI_FLASH_PageSize; + #endif + SPIFlash.endWrite(); + } + else if (assetType == ASSET_TYPE_FONT) { + Pic_Write_Addr = UNIGBK_FLASH_ADDR; + do { + watchdog_refresh(); + pbr = file.read(public_buf, BMP_WRITE_BUF_LEN); + W25QXX.SPI_FLASH_BufferWrite(public_buf, Pic_Write_Addr, pbr); + Pic_Write_Addr += pbr; + } while (pbr >= BMP_WRITE_BUF_LEN); + } + + file.close(); + + #if ENABLED(MARLIN_DEV_MODE) + SERIAL_ECHOLNPAIR("Asset added: ", fn); + #endif + } + + void UpdateAssets() { + if (!card.isMounted()) return; + SdFile dir, root = card.getroot(); + if (dir.open(&root, assetsPath, O_RDONLY)) { + + disp_assets_update(); + disp_assets_update_progress("Erasing pics..."); + watchdog_refresh(); + spiFlashErase_PIC(); + #if HAS_SPI_FLASH_FONT + disp_assets_update_progress("Erasing fonts..."); + watchdog_refresh(); + spiFlashErase_FONT(); + #endif + + disp_assets_update_progress("Reading files..."); + dir_t d; + while (dir.readDir(&d, card.longFilename) > 0) { + // If we dont get a long name, but gets a short one, try it + if (card.longFilename[0] == 0 && d.name[0] != 0) + dosName2LongName((const char*)d.name, card.longFilename); + if (card.longFilename[0] == 0) continue; + if (card.longFilename[0] == '.') continue; + + int8_t a = arrayFindStr(assets, COUNT(assets), card.longFilename); + if (a >= 0 && a < (int8_t)COUNT(assets)) { + uint8_t assetType = ASSET_TYPE_ICON; + if (strstr(assets[a], "_logo")) + assetType = ASSET_TYPE_LOGO; + else if (strstr(assets[a], "_titlelogo")) + assetType = ASSET_TYPE_TITLE_LOGO; + else if (strstr(assets[a], "_preview")) + assetType = ASSET_TYPE_G_PREVIEW; + + loadAsset(dir, d, assets[a], assetType); + + continue; + } + + #if HAS_SPI_FLASH_FONT + a = arrayFindStr(fonts, COUNT(fonts), card.longFilename); + if (a >= 0 && a < (int8_t)COUNT(fonts)) + loadAsset(dir, d, fonts[a], ASSET_TYPE_FONT); + #endif + } + dir.rename(&root, bakPath); + } + dir.close(); + + #if ENABLED(MARLIN_DEV_MODE) + uint8_t pic_counter = 0; + W25QXX.SPI_FLASH_BufferRead(&pic_counter, PIC_COUNTER_ADDR, 1); + SERIAL_ECHOLNPAIR("Total assets loaded: ", pic_counter); + SERIAL_ECHOLNPAIR("Total Uncompressed: ", totalSizes, ", Compressed: ", totalCompressed); + #endif + } + + #if HAS_SPI_FLASH_FONT + void spi_flash_read_test() { W25QXX.SPI_FLASH_BufferRead(public_buf, UNIGBK_FLASH_ADDR, BMP_WRITE_BUF_LEN); } + #endif + +#endif // SDSUPPORT + +void Pic_Read(uint8_t *Pname, uint8_t *P_Rbuff) { + uint8_t i, j; + uint8_t Pic_cnt; + uint32_t tmp_cnt = 0; + PIC_MSG PIC; + + W25QXX.SPI_FLASH_BufferRead(&Pic_cnt, PIC_COUNTER_ADDR, 1); + if (Pic_cnt == 0xFF) + Pic_cnt = 0; + + for (i = 0; i < Pic_cnt; i++) { + j = 0; + do { + W25QXX.SPI_FLASH_BufferRead(&PIC.name[j], PIC_NAME_ADDR + tmp_cnt, 1); + tmp_cnt++; + } while (PIC.name[j++] != '\0'); + //pic size + W25QXX.SPI_FLASH_BufferRead(PIC.size.bytes, PIC_SIZE_ADDR + i * 4, 4); + + if ((strcmp((char*)Pname, (char*)PIC.name)) == 0) { + W25QXX.SPI_FLASH_BufferRead((uint8_t *)P_Rbuff, PIC_DATA_ADDR_TFT35 + i * PER_PIC_MAX_SPACE_TFT35, PIC.size.dwords); + break; + } + } +} + +void lv_pic_test(uint8_t *P_Rbuff, uint32_t addr, uint32_t size) { + #if HAS_SPI_FLASH_COMPRESSION + if (currentFlashPage == 0) + SPIFlash.beginRead(addr); + SPIFlash.readData(P_Rbuff, size); + currentFlashPage++; + #else + W25QXX.init(SPI_QUARTER_SPEED); + W25QXX.SPI_FLASH_BufferRead((uint8_t *)P_Rbuff, addr, size); + #endif +} + +#if HAS_SPI_FLASH_FONT + void get_spi_flash_data(const char *rec_buf, int addr, int size) { + W25QXX.init(SPI_QUARTER_SPEED); + W25QXX.SPI_FLASH_BufferRead((uint8_t *)rec_buf, UNIGBK_FLASH_ADDR + addr, size); + } +#endif + +uint32_t logo_addroffset = 0; +void Pic_Logo_Read(uint8_t *LogoName, uint8_t *Logo_Rbuff, uint32_t LogoReadsize) { + W25QXX.init(SPI_QUARTER_SPEED); + W25QXX.SPI_FLASH_BufferRead(Logo_Rbuff, PIC_LOGO_ADDR + logo_addroffset, LogoReadsize); + logo_addroffset += LogoReadsize; + if (logo_addroffset >= LOGO_MAX_SIZE_TFT35) + logo_addroffset = 0; +} + +uint32_t default_view_addroffset = 0; +void default_view_Read(uint8_t *default_view_Rbuff, uint32_t default_view_Readsize) { + W25QXX.init(SPI_QUARTER_SPEED); + W25QXX.SPI_FLASH_BufferRead(default_view_Rbuff, DEFAULT_VIEW_ADDR_TFT35 + default_view_addroffset, default_view_Readsize); + default_view_addroffset += default_view_Readsize; + if (default_view_addroffset >= DEFAULT_VIEW_MAX_SIZE) + default_view_addroffset = 0; +} + +#if HAS_BAK_VIEW_IN_FLASH + uint32_t flash_view_addroffset = 0; + void flash_view_Read(uint8_t *flash_view_Rbuff, uint32_t flash_view_Readsize) { + W25QXX.init(SPI_QUARTER_SPEED); + W25QXX.SPI_FLASH_BufferRead(flash_view_Rbuff, BAK_VIEW_ADDR_TFT35 + flash_view_addroffset, flash_view_Readsize); + flash_view_addroffset += flash_view_Readsize; + if (flash_view_addroffset >= FLASH_VIEW_MAX_SIZE) + flash_view_addroffset = 0; + } +#endif + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h new file mode 100644 index 0000000..83d7431 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/pic_manager.h @@ -0,0 +1,168 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "../../../../inc/MarlinConfig.h" + +#include "../../../../libs/W25Qxx.h" + +#include <lvgl.h> + +#include <stdint.h> +#include <string.h> + +#ifndef HAS_SPI_FLASH_FONT + #define HAS_SPI_FLASH_FONT 1 // Disabled until fix the font load code +#endif +#ifndef HAS_GCODE_PREVIEW + #define HAS_GCODE_PREVIEW 1 +#endif +#ifndef HAS_LANG_SELECT_SCREEN + #define HAS_LANG_SELECT_SCREEN 1 +#endif +#ifndef HAS_BAK_VIEW_IN_FLASH + #define HAS_BAK_VIEW_IN_FLASH 1 +#endif +#ifndef HAS_GCODE_DEFAULT_VIEW_IN_FLASH + #define HAS_GCODE_DEFAULT_VIEW_IN_FLASH 1 +#endif +#ifndef HAS_LOGO_IN_FLASH + #define HAS_LOGO_IN_FLASH 1 +#endif +#ifndef SPI_FLASH_SIZE + #define SPI_FLASH_SIZE 0x1000000 // 16MB +#endif + +#define PIC_MAX_CN 100 // Maximum number of pictures +#define PIC_NAME_MAX_LEN 50 // Picture name maximum length + +#define LOGO_MAX_SIZE_TFT35 (300*1024) +#define LOGO_MAX_SIZE_TFT32 (150*1024) +#define TITLELOGO_MAX_SIZE (150*1024) // Little logo maximum +#define DEFAULT_VIEW_MAX_SIZE (200*200*2) +#define FLASH_VIEW_MAX_SIZE (200*200*2) + +#define PER_PIC_MAX_SPACE_TFT35 (9*1024) +#define PER_PIC_MAX_SPACE_TFT32 (16*1024) +#define PER_FONT_MAX_SPACE (16*1024) + +#if SPI_FLASH_SIZE == 0x200000 + //pic + //Robin_pro pic addr + #define PIC_NAME_ADDR 0x001000 // Pic information addr + #define PIC_SIZE_ADDR 0x001800 // Pic size information addr + #define PIC_COUNTER_ADDR 0x002000 // Pic total number + #define PER_PIC_SAVE_ADDR 0x000000 // Storage address of each picture + #define PIC_LOGO_ADDR 0x000000 // Logo addr + #define PIC_DATA_ADDR 0x003000 // + + // TFT35 + #define DEFAULT_VIEW_ADDR_TFT35 0x1EA070 + #define BAK_VIEW_ADDR_TFT35 (DEFAULT_VIEW_ADDR_TFT35+90*1024) + #define PIC_ICON_LOGO_ADDR_TFT35 (BAK_VIEW_ADDR_TFT35+80*1024) + #define PIC_DATA_ADDR_TFT35 0x003000 // (PIC_ICON_LOGO_ADDR_TFT35+350*1024) //0xC5800 + + #define PIC_DATA_ADDR_TFT32 0x00F000 + #define PIC_ICON_LOGO_ADDR_TFT32 0x5D8000 + #define PIC_OTHER_SIZE_ADDR_TFT32 0x5EE000 + + // font + #define FONTINFOADDR 0x150000 // 6M -- font addr + #define UNIGBK_FLASH_ADDR (FONTINFOADDR+4096) // 4*1024 + +#else + //pic + // pic addr + #define PIC_NAME_ADDR 0x003000 // Pic information addr + #define PIC_SIZE_ADDR 0x007000 // Pic size information addr + #define PIC_COUNTER_ADDR 0x008000 // Pic total number + #define PIC_LOGO_ADDR 0x009000 // Logo addr + + // TFT35 + #define DEFAULT_VIEW_ADDR_TFT35 0xC5800 + #define BAK_VIEW_ADDR_TFT35 (DEFAULT_VIEW_ADDR_TFT35+90*1024) + #define PIC_ICON_LOGO_ADDR_TFT35 (BAK_VIEW_ADDR_TFT35+80*1024) + #define PIC_DATA_ADDR_TFT35 (PIC_ICON_LOGO_ADDR_TFT35+350*1024) //0xC5800 + + // TFT32 + #define PIC_DATA_ADDR_TFT32 0x02F000 + #define PIC_ICON_LOGO_ADDR_TFT32 0x5D8000 + #define PIC_OTHER_SIZE_ADDR_TFT32 0x5EE000 + + // font + #define FONTINFOADDR 0x600000 // 6M -- font addr + #define UNIGBK_FLASH_ADDR (FONTINFOADDR+4096) // 4*1024 + #define GBK_FLASH_ADDR (UNIGBK_FLASH_ADDR+180224) // 176*1024 + +#endif + +// Flash flag +#define REFLSHE_FLGA_ADD (0X800000-32) + +// SD card information first addr +#define VAR_INF_ADDR 0x000000 +#define FLASH_INF_VALID_FLAG 0x20201118 + +//Store some gcode commands, such as auto leveling commands +#define GCODE_COMMAND_ADDR VAR_INF_ADDR + 3*1024 +#define AUTO_LEVELING_COMMAND_ADDR GCODE_COMMAND_ADDR +#define OTHERS_COMMAND_ADDR_1 AUTO_LEVELING_COMMAND_ADDR + 100 +#define OTHERS_COMMAND_ADDR_2 OTHERS_COMMAND_ADDR_1 + 100 +#define OTHERS_COMMAND_ADDR_3 OTHERS_COMMAND_ADDR_2 + 100 +#define OTHERS_COMMAND_ADDR_4 OTHERS_COMMAND_ADDR_3 + 100 + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +union union32 { + uint8_t bytes[4]; + uint32_t dwords; +}; + +// pic information +struct pic_msg { + uint8_t name[PIC_NAME_MAX_LEN]; + union union32 size; +}; + +typedef struct pic_msg PIC_MSG; + +#define BMP_WRITE_BUF_LEN 512 + +#define PICINFOADDR 0x1000 + +#define PIC_SIZE_xM 6 +#define FONT_SIZE_xM 2 + +extern void Pic_Read(uint8_t *Pname, uint8_t *P_Rbuff); +extern void Pic_Logo_Read(uint8_t *LogoName,uint8_t *Logo_Rbuff,uint32_t LogoReadsize); +extern void lv_pic_test(uint8_t *P_Rbuff, uint32_t addr, uint32_t size); +extern uint32_t lv_get_pic_addr(uint8_t *Pname); +extern void get_spi_flash_data(const char *rec_buf, int offset, int size); +extern void spi_flash_read_test(); +extern void default_view_Read(uint8_t *default_view_Rbuff, uint32_t default_view_Readsize); +extern void flash_view_Read(uint8_t *flash_view_Rbuff, uint32_t flash_view_Readsize); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.cpp b/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.cpp new file mode 100644 index 0000000..379eb42 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.cpp @@ -0,0 +1,250 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include <lv_conf.h> + +#include "../../../../gcode/gcode.h" +#include "../../../../module/temperature.h" +#include "../../../../module/planner.h" +#include "../../../../module/motion.h" +#include "../../../../sd/cardreader.h" +#include "../../../../inc/MarlinConfig.h" +#include "../../../../MarlinCore.h" +#include "../../../../gcode/queue.h" + +#if ENABLED(POWER_LOSS_RECOVERY) + #include "../../../../feature/powerloss.h" +#endif + +extern uint32_t To_pre_view; +extern bool flash_preview_begin, default_preview_flg, gcode_preview_over; +void esp_port_begin(uint8_t interrupt); +void printer_state_polling() { + char str_1[16]; + if (uiCfg.print_state == PAUSING) { + lv_clear_cur_ui(); + lv_draw_dialog(DIALOG_TYPE_MACHINE_PAUSING_TIPS); + #if ENABLED(SDSUPPORT) + while(queue.length) { + queue.advance(); + } + planner.synchronize(); + gcode.process_subcommands_now_P(PSTR("M25")); + //save the positon + uiCfg.current_x_position_bak = current_position.x; + uiCfg.current_y_position_bak = current_position.y; + uiCfg.current_z_position_bak = current_position.z; + + if (gCfgItems.pausePosZ != (float)-1) { + gcode.process_subcommands_now_P(PSTR("G91")); + sprintf_P(public_buf_l, PSTR("G1 Z%s"), dtostrf(gCfgItems.pausePosZ, 1, 1, str_1)); + gcode.process_subcommands_now(public_buf_l); + gcode.process_subcommands_now_P(PSTR("G90")); + } + if (gCfgItems.pausePosX != (float)-1) { + sprintf_P(public_buf_l, PSTR("G1 X%s"), dtostrf(gCfgItems.pausePosX, 1, 1, str_1)); + gcode.process_subcommands_now(public_buf_l); + } + if (gCfgItems.pausePosY != (float)-1) { + sprintf_P(public_buf_l, PSTR("G1 Y%s"), dtostrf(gCfgItems.pausePosY, 1, 1, str_1)); + gcode.process_subcommands_now(public_buf_l); + } + uiCfg.print_state = PAUSED; + uiCfg.current_e_position_bak = current_position.e; + + gCfgItems.pause_reprint = true; + update_spi_flash(); + lv_clear_cur_ui(); + lv_draw_return_ui(); + #endif + } + + if (uiCfg.print_state == PAUSED) { + } + + if (uiCfg.print_state == RESUMING) { + if (IS_SD_PAUSED()) { + if (gCfgItems.pausePosX != (float)-1) { + sprintf_P(public_buf_m, PSTR("G1 X%s"), dtostrf(uiCfg.current_x_position_bak, 1, 1, str_1)); + gcode.process_subcommands_now(public_buf_m); + } + if (gCfgItems.pausePosY != (float)-1) { + sprintf_P(public_buf_m, PSTR("G1 Y%s"), dtostrf(uiCfg.current_y_position_bak, 1, 1, str_1)); + gcode.process_subcommands_now(public_buf_m); + } + if (gCfgItems.pausePosZ != (float)-1) { + ZERO(public_buf_m); + sprintf_P(public_buf_m, PSTR("G1 Z%s"), dtostrf(uiCfg.current_z_position_bak, 1, 1, str_1)); + gcode.process_subcommands_now(public_buf_m); + } + gcode.process_subcommands_now_P(M24_STR); + uiCfg.print_state = WORKING; + start_print_time(); + + gCfgItems.pause_reprint = false; + update_spi_flash(); + } + } + #if ENABLED(POWER_LOSS_RECOVERY) + if (uiCfg.print_state == REPRINTED) { + #if HAS_HOTEND + HOTEND_LOOP() { + const int16_t et = recovery.info.target_temperature[e]; + if (et) { + #if HAS_MULTI_HOTEND + sprintf_P(public_buf_m, PSTR("T%i"), e); + gcode.process_subcommands_now(public_buf_m); + #endif + sprintf_P(public_buf_m, PSTR("M109 S%i"), et); + gcode.process_subcommands_now(public_buf_m); + } + } + #endif + + recovery.resume(); + #if 0 + // Move back to the saved XY + char str_1[16], str_2[16]; + sprintf_P(public_buf_m, PSTR("G1 X%s Y%s F2000"), + dtostrf(recovery.info.current_position.x, 1, 3, str_1), + dtostrf(recovery.info.current_position.y, 1, 3, str_2) + ); + gcode.process_subcommands_now(public_buf_m); + + if (gCfgItems.pause_reprint && gCfgItems.pausePosZ != -1.0f) { + gcode.process_subcommands_now_P(PSTR("G91")); + sprintf_P(public_buf_l, PSTR("G1 Z-%.1f"), gCfgItems.pausePosZ); + gcode.process_subcommands_now(public_buf_l); + gcode.process_subcommands_now_P(PSTR("G90")); + } + #endif + uiCfg.print_state = WORKING; + start_print_time(); + + gCfgItems.pause_reprint = false; + update_spi_flash(); + } + #endif + + if (uiCfg.print_state == WORKING) + filament_check(); + + TERN_(MKS_WIFI_MODULE, wifi_looping()); +} + +void filament_pin_setup() { + #if PIN_EXISTS(MT_DET_1) + SET_INPUT_PULLUP(MT_DET_1_PIN); + #endif + #if PIN_EXISTS(MT_DET_2) + SET_INPUT_PULLUP(MT_DET_2_PIN); + #endif + #if PIN_EXISTS(MT_DET_3) + SET_INPUT_PULLUP(MT_DET_3_PIN); + #endif +} + +void filament_check() { + #if (PIN_EXISTS(MT_DET_1) || PIN_EXISTS(MT_DET_2) || PIN_EXISTS(MT_DET_3)) + const int FIL_DELAY = 20; + #endif + #if PIN_EXISTS(MT_DET_1) + static int fil_det_count_1 = 0; + if (!READ(MT_DET_1_PIN) && !MT_DET_PIN_INVERTING) + fil_det_count_1++; + else if (READ(MT_DET_1_PIN) && MT_DET_PIN_INVERTING) + fil_det_count_1++; + else if (fil_det_count_1 > 0) + fil_det_count_1--; + + if (!READ(MT_DET_1_PIN) && !MT_DET_PIN_INVERTING) + fil_det_count_1++; + else if (READ(MT_DET_1_PIN) && MT_DET_PIN_INVERTING) + fil_det_count_1++; + else if (fil_det_count_1 > 0) + fil_det_count_1--; + #endif + + #if PIN_EXISTS(MT_DET_2) + static int fil_det_count_2 = 0; + if (!READ(MT_DET_2_PIN) && !MT_DET_PIN_INVERTING) + fil_det_count_2++; + else if (READ(MT_DET_2_PIN) && MT_DET_PIN_INVERTING) + fil_det_count_2++; + else if (fil_det_count_2 > 0) + fil_det_count_2--; + + if (!READ(MT_DET_2_PIN) && !MT_DET_PIN_INVERTING) + fil_det_count_2++; + else if (READ(MT_DET_2_PIN) && MT_DET_PIN_INVERTING) + fil_det_count_2++; + else if (fil_det_count_2 > 0) + fil_det_count_2--; + #endif + + #if PIN_EXISTS(MT_DET_3) + static int fil_det_count_3 = 0; + if (!READ(MT_DET_3_PIN) && !MT_DET_PIN_INVERTING) + fil_det_count_3++; + else if (READ(MT_DET_3_PIN) && MT_DET_PIN_INVERTING) + fil_det_count_3++; + else if (fil_det_count_3 > 0) + fil_det_count_3--; + + if (!READ(MT_DET_3_PIN) && !MT_DET_PIN_INVERTING) + fil_det_count_3++; + else if (READ(MT_DET_3_PIN) && MT_DET_PIN_INVERTING) + fil_det_count_3++; + else if (fil_det_count_3 > 0) + fil_det_count_3--; + #endif + + if (false + #if PIN_EXISTS(MT_DET_1) + || fil_det_count_1 >= FIL_DELAY + #endif + #if PIN_EXISTS(MT_DET_2) + || fil_det_count_2 >= FIL_DELAY + #endif + #if PIN_EXISTS(MT_DET_3) + || fil_det_count_3 >= FIL_DELAY + #endif + ) { + lv_clear_cur_ui(); + TERN_(SDSUPPORT, card.pauseSDPrint()); + stop_print_time(); + uiCfg.print_state = PAUSING; + + if (gCfgItems.from_flash_pic) + flash_preview_begin = true; + else + default_preview_flg = true; + + lv_draw_printing(); + } +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.h b/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.h new file mode 100644 index 0000000..f304158 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/printer_operation.h @@ -0,0 +1,36 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +#define MIN_FILE_PRINTED 100 //5000 + +extern void printer_state_polling(); +extern void filament_pin_setup(); +extern void filament_check(); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_en.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_en.h new file mode 100644 index 0000000..78abb21 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_en.h @@ -0,0 +1,751 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +//****************英文***************************// +#define MACHINE_CONFIG_EN "Config" + +#define NEXT_EN "Next" +#define PREVIOUS_EN "Previous" +#define DEFAULT_EN "Default" +#define KEY_BACK_EN "Del" +#define KEY_REST_EN "Reset" +#define KEY_CONFIRM_EN "Confirm" + +#define KEYBOARD_KEY0_EN "0" +#define KEYBOARD_KEY1_EN "1" +#define KEYBOARD_KEY2_EN "2" +#define KEYBOARD_KEY3_EN "3" +#define KEYBOARD_KEY4_EN "4" +#define KEYBOARD_KEY5_EN "5" +#define KEYBOARD_KEY6_EN "6" +#define KEYBOARD_KEY7_EN "7" +#define KEYBOARD_KEY8_EN "8" +#define KEYBOARD_KEY9_EN "9" +#define KEYBOARD_KEY_POINT_EN "." +#define KEYBOARD_KEY_NEGATIVE_EN "-" + +#define MACHINE_PARA_TITLE_EN "Config" +#define MACHINE_TYPE_CNOFIG_EN "Machine settings" +#define MOTOR_CONFIG_EN "Motor settings" +#define MACHINE_LEVELING_CONFIG_EN "Leveling settings" +#define ADVANCE_CONFIG_EN "Advanced settings" + +#define MACHINE_CONFIG_TITLE_EN "Machine Settings" +#define MACHINE_TYPE_EN "Machine type" +#define MACHINE_STROKE_EN "Machine Size" +#define MACHINE_HOMEDIR_EN "Home direction" +#define MACHINE_ENDSTOP_TYPE_EN "Endstop type" +#define MACHINE_FILAMENT_CONFIG_EN "Filament settings" + +#define MACHINE_TYPE_CONFIG_TITLE_EN "Machine Settings>Machine type" +#define MACHINE_TYPE_XYZ_EN "XYZ Machine" +#define MACHINE_TYPE_DELTA_EN "Delta Machine" +#define MACHINE_TYPE_COREXY_EN "Corexy Machine" + +#define MACHINE_STROKE_CONF_TITLE_EN "Machine Settings>Machine Size" +#define X_MAX_LENGTH_EN "X-axis maximum stroke" +#define Y_MAX_LENGTH_EN "Y-axis maximum stroke" +#define Z_MAX_LENGTH_EN "Z-axis maximum stroke" + +#define X_MIN_LENGTH_EN "X-axis minimum stroke" +#define Y_MIN_LENGTH_EN "Y-axis minimum stroke" +#define Z_MIN_LENGTH_EN "Z-axis minimum stroke" + +#define HOME_DIR_CONF_TITLE_EN "Machine Settings>Home direction" +#define HOME_DIR_X_EN "X-axis home direction" +#define HOME_DIR_Y_EN "Y-axis home direction" +#define HOME_DIR_Z_EN "Z-axis home direction" +#define HOME_MIN_EN "MIN" +#define HOME_MAX_EN "MAX" + +#define ENDSTOP_CONF_TITLE_EN "Machine Settings>Endstop type" +#define MIN_ENDSTOP_X_EN "X-axis minimum Endstop" +#define MIN_ENDSTOP_Y_EN "Y-axis minimum Endstop" +#define MIN_ENDSTOP_Z_EN "Z-axis minimum Endstop" +#define MAX_ENDSTOP_X_EN "X-axis maximum Endstop" +#define MAX_ENDSTOP_Y_EN "Y-axis maximum Endstop" +#define MAX_ENDSTOP_Z_EN "Z-axis maximum Endstop" +#define ENDSTOP_FIL_EN "Filament sensor" +#define ENDSTOP_LEVEL_EN "Leveling sensor" +#define ENDSTOP_OPENED_EN "Open" +#define ENDSTOP_CLOSED_EN "Close" + +#define FILAMENT_CONF_TITLE_EN "Machine Settings>Filament settings" +#define FILAMENT_IN_LENGTH_EN "Load length" +#define FILAMENT_IN_SPEED_EN "Load speed" +#define FILAMENT_TEMPERATURE_EN "Filament temperature" +#define FILAMENT_OUT_LENGTH_EN "Unload length" +#define FILAMENT_OUT_SPEED_EN "Unload speed" + +#define LEVELING_CONF_TITLE_EN "Machine Settings>Leveling settings" +#define LEVELING_PARA_CONF_EN "Leveling settings" +#define LEVELING_MANUAL_POS_EN "Manual leveling coordinate settings" +#define LEVELING_AUTO_COMMAND_EN "AutoLeveling command settings" +#define LEVELING_AUTO_ZOFFSET_EN "Nozzle-to-probe offsets settings" +#define LEVELING_TOUCHMI_EN "Settings-TouchMi-Probe" +#define TM_INIT_EN "Init" +#define TM_ZOFFSETPOS_EN "Zoffset+" +#define TM_ZOFFSETNEG_EN "Zoffset-" +#define TM_SAVE_EN "Save" +#define TM_TEST_EN "Test" + +#define BLTOUCH_LEVELING_TITTLE_EN "Machine Settings>BL-Touch Probe" +#define BLTOUCH_LEVELING_EN "BL-Touch Probe" +#define BLTOUCH_INIT_EN "Init" +#define BLTOUCH_ZOFFSETPOS_EN "Zoffset+" +#define BLTOUCH_ZOFFSETNEG_EN "Zoffset-" +#define BLTOUCH_SAVE_EN "Save" +#define BLTOUCH_TEST_EN "Test" + +#define LEVELING_PARA_CONF_TITLE_EN "leveling setting" +#define AUTO_LEVELING_ENABLE_EN "Enable auto leveling" +#define BLTOUCH_LEVELING_ENABLE_EN "Enable BLtouch" +#define PROBE_PORT_EN "Probe connector" +#define PROBE_X_OFFSET_EN "Probe X-axis offset" +#define PROBE_Y_OFFSET_EN "Probe Y-axis offset" +#define PROBE_Z_OFFSET_EN "Probe Z-axis offset" +#define PROBE_XY_SPEED_EN "Probe XY-axis speed" +#define PROBE_Z_SPEED_EN "Probe Z-axis speed" +#define ENABLE_EN "YES" +#define DISABLE_EN "NO" +#define LOCKED_EN "N/A" +#define Z_MIN_EN "ZMin" +#define Z_MAX_EN "ZMax" + +#define DELTA_LEVEL_CONF_TITLE_EN "Delta Machine settings" +#define DELTA_LEVEL_CONF_EN "Delta Machine Leveling" +#define DELTA_MACHINE_RADIUS_EN "Machine Radius" +#define DELTA_DIAGONAL_ROD_EN "Machine rod length" +#define DELTA_PRINT_RADIUS_EN "Print radius" +#define DELTA_HEIGHT_EN "Print height" +#define SMOOTH_ROD_OFFSET_EN "Slider offset" +#define EFFECTOR_OFFSET_EN "Effector offset" +#define CALIBRATION_RADIUS_EN "Leveling radius" + +#define XYZ_LEVEL_CONF_TITLE_EN "Cartesian Machine Settings" +#define PROBE_REACH_MAX_LEFT_EN "Probe reaches leftmost position" +#define PROBE_REACH_MAX_RIGHT_EN "Probe reaches rightmost position" +#define PROBE_REACH_MAX_FRONT_EN "Probe reaches front position" +#define PROBE_REACH_MAX_BACK_EN "Probe reaches final position" + +#define TEMPERATURE_CONF_TITLE_EN "Machine Settings>Temperature settings" +#define NOZZLE_CONF_EN "Nozzle settings" +#define HOTBED_CONF_EN "Hotbed settings" +#define PREHEAT_TEMPER_EN "Preset temperature" + +#define NOZZLE_CONF_TITLE_EN "Machine Settings>Nozzle settings" +#define NOZZLECNT_EN "Number of nozzles" +#define NOZZLE_TYPE_EN "E0 Temperature type" +#define NOZZLE_ADJUST_TYPE_EN "PID thermostat" +#define NOZZLE_MIN_TEMPERATURE_EN "lowest temperature" +#define NOZZLE_MAX_TEMPERATURE_EN "Maximum temperature" +#define EXTRUD_MIN_TEMPER_EN "Minimum extrusion temperature" + +#define HOTBED_CONF_TITLE_EN "Machine Settings>Hotbed settings" +#define HOTBED_ADJUST_EN "PID thermostat" +#define HOTBED_MIN_TEMPERATURE_EN "lowest temperature" +#define HOTBED_MAX_TEMPERATURE_EN "Maximum temperature" + +#define MOTOR_CONF_TITLE_EN "Machine Settings>Motor settings" +#define MAXFEEDRATE_CONF_EN "Maximum speed settings" +#define ACCELERATION_CONF_EN "Acceleration settings" +#define JERKCONF_EN "Jerk settings" +#define STEPSCONF_EN "Steps settings" +#define TMC_CURRENT_EN "TMC Current settings" +#define TMC_STEP_MODE_EN "TMC Step mode settings" +#define MOTORDIRCONF_EN "Motor direction settings" +#define HOMEFEEDRATECONF_EN "Home speed setting" + +#define MAXFEEDRATE_CONF_TITLE_EN "Machine Settings>Maximum speed" +#define X_MAXFEEDRATE_EN "X-axis maximum speed" +#define Y_MAXFEEDRATE_EN "Y-axis maximum speed" +#define Z_MAXFEEDRATE_EN "Z-axis maximum speed" +#define E0_MAXFEEDRATE_EN "E0 maximum speed" +#define E1_MAXFEEDRATE_EN "E1 maximum speed" + +#define ACCELERATION_CONF_TITLE_EN "Machine Settings>Acceleration" +#define PRINT_ACCELERATION_EN "Print acceleration" +#define RETRACT_ACCELERATION_EN "Retraction acceleration" +#define TRAVEL_ACCELERATION_EN "Travel acceleration" +#define X_ACCELERATION_EN "X-axis acceleration" +#define Y_ACCELERATION_EN "Y-axis acceleration" +#define Z_ACCELERATION_EN "Z-axis acceleration" +#define E0_ACCELERATION_EN "E0 acceleration" +#define E1_ACCELERATION_EN "E1 acceleration" + +#define JERK_CONF_TITLE_EN "Machine Settings>Jerk speed" +#define X_JERK_EN "X-axis jerk speed" +#define Y_JERK_EN "Y-axis jerk speed" +#define Z_JERK_EN "Z-axis jerk speed" +#define E_JERK_EN "Extruder jerk speed" + +#define STEPS_CONF_TITLE_EN "Machine Settings>Steps settings" +#define X_STEPS_EN "X-axis steps" +#define Y_STEPS_EN "Y-axis steps" +#define Z_STEPS_EN "Z-axis steps" +#define E0_STEPS_EN "E0 steps" +#define E1_STEPS_EN "E1 steps" + +#define TMC_CURRENT_CONF_TITLE_EN "Machine Settings>TMC current settings" +#define X_TMC_CURRENT_EN "X-axis current (mA)" +#define Y_TMC_CURRENT_EN "Y-axis current (mA)" +#define Z_TMC_CURRENT_EN "Z-axis current (mA)" +#define E0_TMC_CURRENT_EN "E0 current (mA)" +#define E1_TMC_CURRENT_EN "E1 current (mA)" + +#define TMC_MODE_CONF_TITLE_EN "Machine Settings>TMC step mode settings" +#define X_TMC_MODE_EN "Whether X-axis enables stealthChop mode" +#define Y_TMC_MODE_EN "Whether Y-axis enables stealthChop mode" +#define Z_TMC_MODE_EN "Whether Z-axis enables stealthChop mode" +#define E0_TMC_MODE_EN "Whether E0 enables stealthChop mode" +#define E1_TMC_MODE_EN "Whether E1 enables stealthChop mode" + +#define MOTORDIR_CONF_TITLE_EN "Machine Settings>Motor direction" +#define X_MOTORDIR_EN "X-axis motor direction invert" +#define Y_MOTORDIR_EN "Y-axis motor direction invert" +#define Z_MOTORDIR_EN "Z-axis motor direction invert" +#define E0_MOTORDIR_EN "E0 motor direction invert" +#define E1_MOTORDIR_EN "E1 motor direction invert" +#define INVERT_P_EN "YES" +#define INVERT_N_EN "NO" + +#define HOMEFEEDRATE_CONF_TITLE_EN "Machine Settings>Home speed" +#define X_HOMESPEED_EN "XY-axis home speed" +#define Y_HOMESPEED_EN "Y-axis home speed" +#define Z_HOMESPEED_EN "Z-axis home speed" + +#define ADVANCED_CONF_TITLE_EN "Machine Settings>Advance" +#define PWROFF_DECTION_EN "power off dection module" +#define PWROFF_AFTER_PRINT_EN "Auto Shutdown after print" +#define HAVE_UPS_EN "Has UPS power supply" +#define Z2_AND_Z2ENDSTOP_CONF_EN "Z2 Settings" +#define ENABLE_PINS_CONF_EN "Enable pins level settings" +#define WIFI_SETTINGS_EN "Wi-Fi parameter settings" +#define HOMING_SENSITIVITY_CONF_EN "Homing sensitivity settings" +#define ENCODER_SETTINGS_EN "Rotary encoder settings" + +#define Z2_AND_Z2ENDSTOP_CONF_TITLE_EN "Z2 Settings" +#define Z2_ENABLE_EN "Z2 Enable" +#define Z2_ENDSTOP_EN "Z2_EndStop Enable" +#define Z2_PORT_EN "Z2 Connector" + +#define ENABLE_PINS_CONF_TITLE_EN "ENABLE_PINS_LEVEL" +#define X_ENABLE_PINS_INVERT_EN "X_ENABLE_PIN_INVERT" +#define Y_ENABLE_PINS_INVERT_EN "Y_ENABLE_PIN_INVERT" +#define Z_ENABLE_PINS_INVERT_EN "Z_ENABLE_PIN_INVERT" +#define E_ENABLE_PINS_INVERT_EN "E_ENABLE_PIN_INVERT" + +#define PAUSE_POSITION_EN "Printing pause position settings" +#define PAUSE_POSITION_X_EN "X-axis position (Absolute position,-1 invalid)" +#define PAUSE_POSITION_Y_EN "Y-axis position (Absolute position,-1 invalid)" +#define PAUSE_POSITION_Z_EN "Z-axis position (Relative position,-1 invalid)" + +#define WIFI_SETTINGS_TITLE_EN "Machine Settings>Wi-Fi Parameter" +#define WIFI_SETTINGS_MODE_EN "Wi-Fi Mode" +#define WIFI_SETTINGS_NAME_EN "Wi-Fi Name: " +#define WIFI_SETTINGS_PASSWORD_EN "Wi-Fi Password: " +#define WIFI_SETTINGS_CLOUD_EN "Do you use cloud services?" +#define WIFI_SETTINGS_CONFIG_EN "Config" +#define WIFI_SETTINGS_EDIT_EN "Edit" +#define WIFI_CONFIG_TIPS_EN "Wi-Fi configuration?" + +#define OFFSET_TITLE_EN "Machine Settings>Offset" +#define OFFSET_X_EN "X offset" +#define OFFSET_Y_EN "Y offset" +#define OFFSET_Z_EN "Z offset" + +#define HOMING_SENSITIVITY_CONF_TITLE_EN "Machine Settings>Sensitivity" +#define X_SENSITIVITY_EN "X-axis sensitivity" +#define Y_SENSITIVITY_EN "Y-axis sensitivity" +#define Z_SENSITIVITY_EN "Z-axis sensitivity" +#define Z2_SENSITIVITY_EN "Z2-axis sensitivity" + +#define ENCODER_CONF_TITLE_EN "Machine Settings>Rotary encoder settings" +#define ENCODER_CONF_TEXT_EN "Is the encoder function used?" + +#define TOOL_TEXT_EN "Tool" +#define PREHEAT_TEXT_EN "Preheat" +#define MOVE_TEXT_EN "Move" +#define HOME_TEXT_EN "Home" +#define PRINT_TEXT_EN "Printing" +#define EXTRUDE_TEXT_EN "Extrusion" +#define LEVELING_TEXT_EN "Leveling" +#define AUTO_LEVELING_TEXT_EN "AutoLevel" +#define SET_TEXT_EN "Settings" +#define MORE_TEXT_EN "More" + +#define ADD_TEXT_EN "Add" +#define DEC_TEXT_EN "Dec" +#define EXTRUDER_1_TEXT_EN "Extrusion1" +#define EXTRUDER_2_TEXT_EN "Extrusion2" +#define HEATBED_TEXT_EN "HeatBed" +#define TEXT_1C_EN "1℃" +#define TEXT_5C_EN "5℃" +#define TEXT_10C_EN "10℃" +#define CLOSE_TEXT_EN "Close" + +#define BACK_TEXT_EN "Back" + +#define TOOL_PREHEAT_EN "Preheat" +#define TOOL_EXTRUDE_EN "Extrusion" +#define TOOL_MOVE_EN "Move" +#define TOOL_HOME_EN "Home" +#define TOOL_LEVELING_EN "Leveling" +#define TOOL_AUTO_LEVELING_EN "AutoLevel" +#define TOOL_FILAMENT_EN "Filament" +#define TOOL_MORE_EN "More" + +#define AXIS_X_ADD_TEXT_EN "X+" +#define AXIS_X_DEC_TEXT_EN "X-" +#define AXIS_Y_ADD_TEXT_EN "Y+" +#define AXIS_Y_DEC_TEXT_EN "Y-" +#define AXIS_Z_ADD_TEXT_EN "Z+" +#define AXIS_Z_DEC_TEXT_EN "Z-" +#define TEXT_01MM_EN "0.1mm" +#define TEXT_1MM_EN "1mm" +#define TEXT_10MM_EN "10mm" + +#define HOME_X_TEXT_EN "X" +#define HOME_Y_TEXT_EN "Y" +#define HOME_Z_TEXT_EN "Z" +#define HOME_ALL_TEXT_EN "Home" +#define HOME_STOPMOVE_EN "Quickstop" + +#define PAGE_UP_TEXT_EN "Page up" +#define PAGE_DOWN_TEXT_EN "Page down" + +#define EXTRUDER_IN_TEXT_EN "In" +#define EXTRUDER_OUT_TEXT_EN "Out" +#define EXTRUDE_1MM_TEXT_EN "1mm" +#define EXTRUDE_5MM_TEXT_EN "5mm" +#define EXTRUDE_10MM_TEXT_EN "10mm" +#define EXTRUDE_LOW_SPEED_TEXT_EN "Low" +#define EXTRUDE_MEDIUM_SPEED_TEXT_EN "Normal" +#define EXTRUDE_HIGH_SPEED_TEXT_EN "High" + +#define LEVELING_POINT1_TEXT_EN "Point1" +#define LEVELING_POINT2_TEXT_EN "Point2" +#define LEVELING_POINT3_TEXT_EN "Point3" +#define LEVELING_POINT4_TEXT_EN "Point4" +#define LEVELING_POINT5_TEXT_EN "Point5" + +#define FILESYS_TEXT_EN "FileSys" +#define WIFI_TEXT_EN "WiFi" +#define FAN_TEXT_EN "Fan" +#define ABOUT_TEXT_EN "About" +#define BREAK_POINT_TEXT_EN "Continue" +#define FILAMENT_TEXT_EN "Filament" +#define LANGUAGE_TEXT_EN "Language" +#define MOTOR_OFF_TEXT_EN "Motor-off" +#define MOTOR_OFF_XY_TEXT_EN "Off-XY" +#define SHUTDOWN_TEXT_EN "Shutdown" +#define MACHINE_PARA_EN "Config" +#define EEPROM_SETTINGS_EN "Eeprom Set" + +#define U_DISK_TEXT_EN "USB" +#define SD_CARD_TEXT_EN "SD" +#define WIFI_NAME_TEXT_EN "WiFi: " +#define WIFI_KEY_TEXT_EN "Key: " +#define WIFI_IP_TEXT_EN "IP: " +#define WIFI_AP_TEXT_EN "State: AP" +#define WIFI_STA_TEXT_EN "State: STA" +#define WIFI_CONNECTED_TEXT_EN "Connected" +#define WIFI_DISCONNECTED_TEXT_EN "Disconnected" +#define WIFI_EXCEPTION_TEXT_EN "Exception" +#define WIFI_RECONNECT_TEXT_EN "Reconnect" +#define CLOUD_TEXT_EN "Cloud" +#define CLOUD_BIND_EN "Bind" +#define CLOUD_UNBIND_EN "Unbind" +#define CLOUD_UNBINDING_EN "Unbinding" +#define CLOUD_DISCONNECTED_EN "Disconnected" +#define CLOUD_UNBINDED_EN "Unbinded" +#define CLOUD_BINDED_EN "Binded" +#define CLOUD_DISABLE_EN "Disable" + +#define FAN_ADD_TEXT_EN "Add" +#define FAN_DEC_TEXT_EN "Dec" +#define FAN_OPEN_TEXT_EN "100%" +#define FAN_HALF_TEXT_EN "50%" +#define FAN_CLOSE_TEXT_EN "Close" +#define FAN_TIPS1_TEXT_EN "FAN" +#define FAN_TIPS2_TEXT_EN "FAN\nClose" + +#define FILAMENT_IN_TEXT_EN "Load" +#define FILAMENT_OUT_TEXT_EN "Unload" +#define FILAMENT_EXT0_TEXT_EN "Extrusion1" +#define FILAMENT_EXT1_TEXT_EN "Extrusion2" +#define FILAMENT_HEAT_TEXT_EN "Preheat" +#define FILAMENT_STOP_TEXT_EN "Stop" +#define FILAMENT_TIPS2_TEXT_EN "T:" +#define FILAMENT_TIPS3_TEXT_EN "Loading..." +#define FILAMENT_TIPS4_TEXT_EN "Unloading..." +#define FILAMENT_TIPS5_TEXT_EN "Temp is too low to go,please heat" +#define FILAMENT_TIPS6_TEXT_EN "Completed" + +#define FILAMENT_CHANGE_TEXT_EN "Please click <Load> \nor <unload>,After \npinter pause." +#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_EN "Heating up the nozzle,\nplease wait..." +#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_EN "Heating up the nozzle,\nplease wait..." +#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_EN "Heat completed,please load filament \nto extruder,and click <confirm> \nfor start loading." +#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_EN "Please load filament to extruder,\nand click <confirm> for start loading." +#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_EN "Heat completed,please \nclick <confirm> for start unloading.!" +#define FILAMENT_DIALOG_LOADING_TIPS_EN "Is loading ,please wait!" +#define FILAMENT_DIALOG_UNLOADING_TIPS_EN "Is unloading,please wait!" +#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_EN "Load filament completed,\nclick <confirm> for return!" +#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_EN "Unload filament completed,\nclick <confirm> for return!" + + +#define PRE_HEAT_EXT_TEXT_EN "E" +#define PRE_HEAT_BED_TEXT_EN "Bed" + +#define FILE_LOADING_EN "Loading......" +#define NO_FILE_AND_CHECK_EN " No files found!\n Check the file system configuration!" + +#define NO_FILE_EN "No files found!" + +#define EXTRUDER_TEMP_TEXT_EN "Temper" +#define EXTRUDER_E_LENGTH1_TEXT_EN "Extrusion1" +#define EXTRUDER_E_LENGTH2_TEXT_EN "Extrusion2" +#define EXTRUDER_E_LENGTH3_TEXT_EN "Extrusion3" + +#define ABOUT_TYPE_TEXT_EN "Type: " +#define ABOUT_VERSION_TEXT_EN "Firmware: " +#define ABOUT_WIFI_TEXT_EN "WiFi: " + +#define PRINTING_OPERATION_EN "Option" +#define PRINTING_PAUSE_EN "Pause" +#define PRINTING_TEMP_EN "Temp." +#define PRINTING_CHANGESPEED_EN "Speed" +#define PRINTING_RESUME_EN "Resume" +#define PRINTING_STOP_EN "Stop" +#define PRINTING_MORE_EN "More" +#define PRINTING_EXTRUDER_EN "Extrusion" +#define PRINTING_MOVE_EN "Move" + +#define EXTRUDER_SPEED_EN "Extrusion" +#define MOVE_SPEED_EN "Move" +#define EXTRUDER_SPEED_STATE_EN "Extrude Speed" +#define MOVE_SPEED_STATE_EN "Move Speed" +#define STEP_1PERCENT_EN "1%" +#define STEP_5PERCENT_EN "5%" +#define STEP_10PERCENT_EN "10%" + +#define TITLE_READYPRINT_EN "ReadyPrint" +#define TITLE_PREHEAT_EN "Preheat" +#define TITLE_MOVE_EN "Move" +#define TITLE_HOME_EN "Home" +#define TITLE_EXTRUDE_EN "Extrusion" +#define TITLE_LEVELING_EN "Leveling" +#define TITLE_SET_EN "Settings" +#define TITLE_MORE_EN "More" +#define TITLE_CHOOSEFILE_EN "ChooseFile" +#define TITLE_PRINTING_EN "Printing" +#define TITLE_OPERATION_EN "Operation" +#define TITLE_ADJUST_EN "Adjust" +#define TITLE_WIRELESS_EN "Wireless" +#define TITLE_FILAMENT_EN "Filament" +#define TITLE_ABOUT_EN "About" +#define TITLE_FAN_EN "Fan" +#define TITLE_LANGUAGE_EN "Language" +#define TITLE_PAUSE_EN "Pause" +#define TITLE_CHANGESPEED_EN "Speed" +#define TITLE_CLOUD_TEXT_EN "Cloud" +#define TITLE_DIALOG_CONFIRM_EN "Confirm" +#define TITLE_FILESYS_EN "FileSys" + +#define AUTO_SHUTDOWN_EN "Auto" +#define MANUAL_SHUTDOWN_EN "Manual" + +#define DIALOG_CONFIRM_EN "Confirm" +#define DIALOG_CANCLE_EN "Cancel" +#define DIALOG_OK_EN "OK" +#define DIALOG_RESET_EN "Reset" +#define DIALOG_RETRY_EN "Retry" +#define DIALOG_DISABLE_EN "Disable" +#define DIALOG_PRINT_MODEL_EN "Print this model?" +#define DIALOG_CANCEL_PRINT_EN "Stop print?" +#define DIALOG_RETRY_EN "Retry" +#define DIALOG_STOP_EN "Stop" +#define DIALOG_REPRINT_FROM_BREAKPOINT_EN "Reprint from breakpoint?" +#define DIALOG_ERROR_TIPS1_EN "Error:no file,please check it again." +#define DIALOG_ERROR_TIPS2_EN "Error:transaction failed.please check display baudrate \nwhether as the same as mainboard!" +#define DIALOG_ERROR_TIPS3_EN "Error:file name or path is too long!" +#define DIALOG_CLOSE_MACHINE_EN "Closing machine......" +#define DIALOG_UNBIND_PRINTER_EN "Unbind the printer?" +#define DIALOG_FILAMENT_NO_PRESS_EN "Filament detection switch is not pressed" +#define DIALOG_PRINT_FINISH_EN "Done print!" +#define DIALOG_PRINT_TIME_EN "Print time: " +#define DIALOG_REPRINT_EN "Print again" +#define DIALOG_WIFI_ENABLE_TIPS_EN "The wifi module is being configured\nplease wait a moment....." +#define DIALOG_PAUSING_TIPS_EN "The machine pauses..." + +#define HOTBED_ENABLE_EN "Enable heatbed" +#define MOTOR_EN_HIGH_LEVEL_EN "High" +#define MOTOR_EN_LOW_LEVEL_EN "Low" + +#define TEXT_WIFI_MENU_TITLE_EN "WI-FI" +#define TEXT_WIFI_SAPCE_EN "space" +#define TEXT_WIFI_LETTER_EN "abc" +#define TEXT_WIFI_DIGITAL_EN "123" +#define TEXT_WIFI_SYMBOL_EN "#+=" +#define TEXT_WIFI_PASSWORD_EN "Password" + +#define TEXT_WIFI_JOINING_EN "Joining Network..." +#define TEXT_WIFI_FAILED_JOIN_EN "Failed to Join Wi-Fi" +#define TEXT_WIFI_WIFI_CONECTED_EN "Wi-Fi Connected" + +#define TEXT_BUTTON_DISCONECTED_EN "Disconnect" +#define TEXT_WIFI_FORGET_EN "Forget Network" +#define TEXT_DISCONECTED_EN "Wi-Fi Connected" + +//wifi-list +#define MAIN_BUILT_EN "Build" +#define MAIN_FILAMENT_EN "Filament" +#define MAIN_SETUP_EN "Setup" +#define MAIN_ABOUT_EN "About" +#define MAIN_MENU_EN "Menu" +#define FILE_MENU_BUILD_EN "Build" +#define FILE_MENU_MENU_EN " < Menu" + +//about +#define ABOUT_TITLE_EN "About" +#define ABOUT_BUILT_MACHINES_EN "Built Machines" +#define ABOUT_SPARK_EN "Spark" +#define ABOUT_VERSION_EN "Version 1.1.0" +#define ABOUT_SERIAL_NUMBER_EN "Serial Number:" +#define ABOUT_S_NUMBER_EN "DCPLX02KFC6P" + +//set +#define SETUP_TITLE_EN "Setup" +#define SETUP_WIFI_EN "Wi-Fi" +#define SETUP_MANUAL_IP_EN "Manual IP" +#define SETUP_WIFI_NOT_CONNECTED_EN "Not Connected" +#define SETUP_WIFI_NETWORK_EN "WiFi_Network" + +//build +#define BUILD_TITLE_EN "Build" +#define BUILD_SD_CARD_EN "SD Card" +#define BUILD_USB_DRIVE_EN "USB Drive" + +//SD card +#define SD_CARD_TITLE_EN "SD Card" +#define SD_CARD_BACK_EN "< Back" +//USB Drive +#define USB_DRIVE_TITLE_EN "USB Drive" +#define USB_DRIVE_BACK_EN "< Back" +#define FILE_PAGES_EN "%d/%d" +#define FILE_NEXT_PAGE_EN "Next Page" + +//BUILD PLATE +#define PLATE_TITLE_EN "Build Plate" +#define PLATE_BACK_EN "< Back" +#define PLATE_CONFIRM_EN "Confirm >" +#define PLATE_TIPS_EN "Confirm that there is a Clear\nBuild Plate installed in the\nmachine." + +//build model +#define MODEL_TITLE_EN "Build Model" +#define MODEL_START_BUILD_EN "Start Build" +#define MODEL_BACK_EN "< Back" + +//building +#define BUILDING_TITLE_EN "Building" +#define BUILDING_MENU_EN "Build Menu" +#define BUILDING_COMPLETED "Build\nComplete" + +//building menu +#define BUILDING_MENU_TITLE_EN "Build Menu" +#define BUILDING_MENU_SETTINGS_EN "Build Settings" +#define BUILDING_MENU_PAUSE_EN "Pause Build" +#define BUILDING_MENU_CANCEL_EN "Cancel Build" +#define BUILDING_MENU_BACK_EN "< Back" + +//build settings +#define SETTINGS_TITLE_EN "Build Settings" +#define SETTINGS_NOZZLE_TEMPER_EN "Nozzle Temp:" +#define SETTINGS_NOZZLE_VALUE_EN "%d" +#define SETTINGS_BED_TEMPER_EN "Bed Temp:" +#define SETTINGS_BED_VALUE_EN "%d" +#define SETTINGS_BUILD_SPEED_EN "Build Speed:" +#define SETTINGS_SPEED_VALUE_EN "Standard" +#define SETTINGS_BACK_EN "< Back" + +//build paused +#define PAUSED_TITLE_EN "Build Paused" +#define PAUSED_RESUME_EN "Resume Build" +#define PAUSED_CANCEL_EN "Cancel Build" +#define PAUSED_BACK_EN "< Back" + +//build cancel +#define CANCEL_TITLE_EN "Cancel Build" +#define CANCEL_BUILD_EN "Cancel Build" +#define CANCEL_TIPS_EN "Are you sure you want to\ncancel this build? The model\nwill be deleted from this\nmachine. It will need to be\nresent from your computer\nbefore it can be built in the\nfuture." +#define CANCEL_BACK_EN "< Back" +#define CANCEL_BUILD_DISPLAY_EN "Build\nCanceled" +#define CANCEL_OVER_PLATE_TIPS_EN "Confirm that the Build Plate\nhas been removed from the\nmachine." + +//filament model enter +#define FILAMENT_MODEL_ENTER_TITLE_EN "Model-PLA" +#define FILAMENT_MODEL_ENTER_BACK_EN "< Back" +#define FILAMENT_MODEL_ENTER_BEGIN_EN "Begin >" +#define FILAMENT_MODEL_ENTER_TIPS_EN "The Model Filament spool\ncompartment is located on\nthe right side of the machine." + +//filament model PLA +#define FILAMENT_MODEL_PLA_TITLE_EN "Model-PLA" +#define FILAMENT_PLA_LOAD_TITLE_EN "Load Filament" +#define FILAMENT_PLA_UNLOAD_TITLE_EN "Unload Filament" +#define FILAMENT_MODEL_PLA_LOAD_EN "Load Filament" +#define FILAMENT_MODEL_PLA_UNLOAD_EN "Unload Filament" +//filament support enter +#define FILAMENT_SUPPORT_ENTER_TITLE_EN "Support-PVA" +#define FILAMENT_SUPPORT_ENTER_BACK_EN "< Back" +#define FILAMENT_SUPPORT_ENTER_BEGIN_EN "Begin >" +#define FILAMENT_SUPPORT_ENTER_TIPS_EN "The Support Filament spool\ncompartment is located on\nthe left side of the machine." +//filament heating +#define FILAMENT_HEATING_LOAD_TITLE_EN "Load Filament" +#define FILAMENT_HEATING_UNLOAD_TITLE_EN "Unload Filament" +#define FILAMENT_HEATING_CANCEL_EN "< Cancel" +#define FILAMENT_HEATING_MATERIAL_EN "Material:" +#define FILAMENT_HEATING_PLA_EN "Model-PLA" +#define FILAMENT_HEATING_TIPS_EN "Print head is heating..." +//rotate left +#define ROTATE_LEFT_LOAD_TITLE_EN "Load Filament" +#define ROTATE_LEFT_UNLOAD_TITLE_EN "Unload Filament" +#define ROTATE_LEFT_CANCEL_EN "< Cancel" +#define ROTATE_LEFT_MATERIAL_EN "Material:" +#define ROTATE_LEFT_PLA_EN "Model-PLA" +#define ROTATE_LEFT_NEXT_EN "Next >" +#define ROTATE_LEFT_TIPS_EN "Rotate extruder selection\ndial to the left." + +//hang spool +#define HANG_SPOOL_TITLE_EN "Load Filament" +#define HANG_SPOOL_PREVIOUS_EN "< Previous" +#define HANG_SPOOL_MATERIAL_EN "Material:" +#define HANG_SPOOL_PLA_EN "Model-PLA" +#define HANG_SPOOL_NEXT_EN "Next >" +#define HANG_SPOOL_TIPS_EN "Hang the spool in the spool\ncompartment as shown." + +//feed filament +#define FEED_FILAMENT_TITLE_EN "Load Filament" +#define FEED_FILAMENT_PREVIOUS_EN "< Previous" +#define FEED_FILAMENT_MATERIAL_EN "Material:" +#define FEED_FILAMENT_PLA_EN "Model-PLA" +#define FEED_FILAMENT_NEXT_EN "Next >" +#define FEED_FILAMENT_TIPS_EN "Feed filament into extruder\nup beyond the gears." + +//feed filament +#define ROTATE_UP_TITLE_EN "Load Filament" +#define ROTATE_UP_PREVIOUS_EN "< Previous" +#define ROTATE_UP_MATERIAL_EN "Material:" +#define ROTATE_UP_PLA_EN "Model-PLA" +#define ROTATE_UP_NEXT_EN "Next >" +#define ROTATE_UP_TIPS_EN "Rotate extruder selection\ndial up." + +//filament begin +#define FEED_BEGIN_TITLE_EN "Load Filament" +#define FEED_BEGIN_MATERIAL_EN "Material:" +#define FEED_BEGIN_PLA_EN "Model-PLA" +#define FEED_BEGIN_NEXT_EN "Next >" +#define FEED_BEGIN_TIPS_EN "Press Next when filament\nbegins to extrude." + +//filament finish +#define FEED_FINISH_TITLE_EN "Load Filament" +#define FEED_FINISH_MATERIAL_EN "Material:" +#define FEED_FINISH_PLA_EN "Model-PLA" +#define FEED_FINISH_NEXT_EN "Finish >" +#define FEED_FINISH_TIPS_EN "Remove filament from the\nnozzle and discard." +//fiament remove +#define REMOVE_SPOOL_TITLE_EN "Unload Filament" +#define REMOVE_SPOOL_PREVIOUS_EN "< Previous" +#define REMOVE_SPOOL_FINISH_EN "Finish >" +#define REMOVE_SPOOL_MATERIAL_EN "Material:" +#define REMOVE_SPOOL_PLA_EN "Model-PLA" +#define REMOVE_SPOOL_TIPS_EN "Remove the spool and pull\nfilament out of the machine." + +#define FILAMENT_SUPPORT_PVA_EN "Support-PVA" +#define LOAD_FINISH_EN "Load\nFilament\nComplete" +#define UNLOAD_FINISH_EN "Unload\nFilament\nComplete" + +//manual ip +#define MANUAL_IP_TITLE_EN "Manual IP" +#define MANUAL_IP_CANCEL_EN "< Cancel" +#define MANUAL_IP_APPLY_EN "Join >" +#define MANUAL_IP_ADDRESS_EN "IP Address" +#define MANUAL_IP_MASK_EN "Subnet Mask" +#define MANUAL_IP_GATEWAY_EN "Default Gateway" +#define MANUAL_IP_SERVER_EN "Name Server" +#define MANUAL_IP_INIT_DATA_EN "0.0.0.0" +#define MANUAL_TEXT_POINT_EN "." +#define MANUAL_TEXT_ENTER_EN "enter" + +#define TEXT_FORGET_TIPS_TITLE_EN "Forget Network" +#define TEXT_FORGET_NETWORK_TIPS1_EN "Are you sure you want to\nforget this network?" +#define TEXT_FORGET_NETWORK_TIPS2_EN "This machine will no longer\njoin this Wi-Fi Network." + +#define TEXT_IPADDRESS_EN "IP Address: " + +#define TEXT_BUILD_FROM_CURA_CANCEL_TIPS1_EN "Are you sure you want to\ncancel this build?" +#define TEXT_BUILD_FROM_CURA_CANCEL_TIPS2_EN "The model will be deleted\nfrom this machine.It will\nneed to be resent from your\ncomputer before it can be\nbuilt in the future." + +#define DIALOG_CONFIRM_EN2 "Confirm" + +#define HEATING_TITLE_EN "Heating" +#define LEVELING_TITLE_EN "Leveling" + +#define ABOUT_SPARK_ADD_EN "Spark+" + +#define TEXT_RECEIVING_DATA_EN "Receiving Data" + +#define TEXT_BABY_STEP_EN "Babystep" + +#define PRINTING_OTHER_LANGUGE "Printing" +#define PRINTING_OPERATION_OTHER_LANGUGE "Operation" +#define PRINTING_PAUSE_OTHER_LANGUGE "Pause" + +#define MESSAGE_PAUSING_EN "Parking..." +#define MESSAGE_CHANGING_EN "Wait for filament change to start" +#define MESSAGE_UNLOAD_EN "Wait for filament unload" +#define MESSAGE_WAITING_EN "Press Button to resume print" +#define MESSAGE_INSERT_EN "Insert filament and press button to continue" +#define MESSAGE_LOAD_EN "Wait for filament load" +#define MESSAGE_PURGE_EN "Wait for filament purge" +#define MESSAGE_RESUME_EN "Wait for print to resume..." +#define MESSAGE_HEAT_EN "Press button to heat nozzle" +#define MESSAGE_HEATING_EN "Nozzle heating Please wait..." +#define MESSAGE_OPTION_EN "Purge more or continue print?" +#define MESSAGE_PURGE_MORE_EN "Purge" +#define MESSAGE_CONTINUE_PRINT_EN "Print" +#define EEPROM_SETTINGS_TITLE_EN "EEPROM Settings" +#define EEPROM_SETTINGS_STORE_EN "Store settings to EEPROM" +#define EEPROM_SETTINGS_READ_EN "Read settings from EEPROM" +#define EEPROM_SETTINGS_REVERT_EN "Revert settings to factory defaults" + +#define EEPROM_STORE_TIPS_EN "Store settings to EEPROM?" +#define EEPROM_READ_TIPS_EN "Read settings from EEPROM?" +#define EEPROM_REVERT_TIPS_EN "Revert settings to factory defaults?" + +#define MORE_CUSTOM1_TEXT_EN USER_DESC_1 +#define MORE_CUSTOM2_TEXT_EN USER_DESC_2 +#define MORE_CUSTOM3_TEXT_EN USER_DESC_3 +#define MORE_CUSTOM4_TEXT_EN USER_DESC_4 +#define MORE_CUSTOM5_TEXT_EN USER_DESC_5 +#define MORE_CUSTOM6_TEXT_EN USER_DESC_6 +#define MORE_CUSTOM7_TEXT_EN USER_DESC_7 diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_fr.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_fr.h new file mode 100644 index 0000000..e65ec43 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_fr.h @@ -0,0 +1,268 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +//*************法文****************************// +#define TOOL_TEXT_FR "prêt" +#define PREHEAT_TEXT_FR "Préchauffe" +#define MOVE_TEXT_FR "Déplace" +#define HOME_TEXT_FR "Acceuil" +#define PRINT_TEXT_FR "Impression" +#define EXTRUDE_TEXT_FR "Extruder" +#define LEVELING_TEXT_FR "Leveling" +#define AUTO_LEVELING_TEXT_FR "AutoLevel" +#define SET_TEXT_FR "Config" +#define MORE_TEXT_FR "Plus" + +#define ADD_TEXT_FR "Ajouter" +#define DEC_TEXT_FR "Réduire" +#define EXTRUDER_1_TEXT_FR "Extr1" +#define EXTRUDER_2_TEXT_FR "Extr2" +#define HEATBED_TEXT_FR "Hotlit" +#define TEXT_1C_FR "1℃" +#define TEXT_5C_FR "5℃" +#define TEXT_10C_FR "10℃" +#define CLOSE_TEXT_FR "Off" + +#define BACK_TEXT_FR "Arrière" + +#define TOOL_PREHEAT_FR "Préchauffe" +#define TOOL_EXTRUDE_FR "Extruder" +#define TOOL_MOVE_FR "Déplace" +#define TOOL_HOME_FR "Acceuil" +#define TOOL_LEVELING_FR "Leveling" +#define TOOL_AUTO_LEVELING_FR "AutoLevel" +#define TOOL_FILAMENT_FR "Filament" +#define TOOL_MORE_FR "Plus" + +#define AXIS_X_ADD_TEXT_FR "X+" +#define AXIS_X_DEC_TEXT_FR "X-" +#define AXIS_Y_ADD_TEXT_FR "Y+" +#define AXIS_Y_DEC_TEXT_FR "Y-" +#define AXIS_Z_ADD_TEXT_FR "Z+" +#define AXIS_Z_DEC_TEXT_FR "Z-" +#define TEXT_01MM_FR "0.1mm" +#define TEXT_1MM_FR "1mm" +#define TEXT_10MM_FR "10mm" + +#define HOME_X_TEXT_FR "X" +#define HOME_Y_TEXT_FR "Y" +#define HOME_Z_TEXT_FR "Z" +#define HOME_ALL_TEXT_FR "ALL" +#define HOME_STOPMOVE_FR "Quickstop" + +#define PAGE_UP_TEXT_FR "En haut" +#define PAGE_DOWN_TEXT_FR "En bas" + +#define EXTRUDER_IN_TEXT_FR "Insérer" +#define EXTRUDER_OUT_TEXT_FR "éjecter" +#define EXTRUDE_1MM_TEXT_FR "1mm" +#define EXTRUDE_5MM_TEXT_FR "5mm" +#define EXTRUDE_10MM_TEXT_FR "10mm" +#define EXTRUDE_LOW_SPEED_TEXT_FR "Lente" +#define EXTRUDE_MEDIUM_SPEED_TEXT_FR "Moyen" +#define EXTRUDE_HIGH_SPEED_TEXT_FR "Rapide" + +#define LEVELING_POINT1_TEXT_FR "Premier" +#define LEVELING_POINT2_TEXT_FR "Seconde" +#define LEVELING_POINT3_TEXT_FR "Troisième" +#define LEVELING_POINT4_TEXT_FR "Quatrième" +#define LEVELING_POINT5_TEXT_FR "Cinquième" + +#define FILESYS_TEXT_FR "Fichier" +#define WIFI_TEXT_FR "WiFi" +#define FAN_TEXT_FR "Fan" +#define ABOUT_TEXT_FR "A propos" +#define BREAK_POINT_TEXT_FR "Continuer" +#define FILAMENT_TEXT_FR "Remplacer" +#define LANGUAGE_TEXT_FR "Langue" +#define MOTOR_OFF_TEXT_FR "M-hors" +#define MOTOR_OFF_XY_TEXT_FR "M-hors-XY" +#define SHUTDOWN_TEXT_FR "Eteindre" +#define MACHINE_PARA_FR "Config" +#define EEPROM_SETTINGS_FR "Eeprom Set" + +#define U_DISK_TEXT_FR "Clé usb" +#define SD_CARD_TEXT_FR "Carte SD" +#define WIFI_NAME_TEXT_FR "WiFi: " +#define WIFI_KEY_TEXT_FR "Key: " +#define WIFI_IP_TEXT_FR "IP: " +#define WIFI_AP_TEXT_FR "Etat: AP" +#define WIFI_STA_TEXT_FR "Etat: STA" +#define WIFI_CONNECTED_TEXT_FR "Connecté" +#define WIFI_DISCONNECTED_TEXT_FR "Déconnecté" +#define WIFI_EXCEPTION_TEXT_FR "Exception" +#define WIFI_RECONNECT_TEXT_FR "Reconnect" +#define CLOUD_TEXT_FR "Cloud" +#define CLOUD_BIND_FR "Lié" +#define CLOUD_UNBIND_FR "Délier" +#define CLOUD_UNBINDING_FR "Délier" +#define CLOUD_DISCONNECTED_FR "Déconnecté" +#define CLOUD_UNBINDED_FR "Délier" +#define CLOUD_BINDED_FR "Lié" +#define CLOUD_DISABLE_FR "Désactiver" + +#define FAN_ADD_TEXT_FR "Ajouter" +#define FAN_DEC_TEXT_FR "Réduire" +#define FAN_OPEN_TEXT_FR "100%" +#define FAN_HALF_TEXT_FR "50%" +#define FAN_CLOSE_TEXT_FR "0%" +#define FAN_TIPS1_TEXT_FR "ventilateur" +#define FAN_TIPS2_TEXT_FR "ventilateur\n0" + +#define FILAMENT_IN_TEXT_FR "Insérer" +#define FILAMENT_OUT_TEXT_FR "éjecter" +#define FILAMENT_EXT0_TEXT_FR "Extr1" +#define FILAMENT_EXT1_TEXT_FR "Extr2" +#define FILAMENT_HEAT_TEXT_FR "Preheat" +#define FILAMENT_STOP_TEXT_FR "Arrêter" +#define FILAMENT_TIPS2_TEXT_FR "T:" +#define FILAMENT_TIPS3_TEXT_FR "Insérer le filament..." +#define FILAMENT_TIPS4_TEXT_FR "éjecter le filament..." +#define FILAMENT_TIPS5_TEXT_FR "Température trop basse pour démarrer, chauffez svp" +#define FILAMENT_TIPS6_TEXT_FR "Terminé" + +#define FILAMENT_CHANGE_TEXT_FR "Please click <Load> \nor <unload>,After \npinter pause." +#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_FR "Heating up the nozzle,\nplease wait..." +#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_FR "Heating up the nozzle,\nplease wait..." +#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_FR "Heat completed,please load filament \nto extruder,and click <confirm> \nfor start loading." +#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_FR "Please load filament to extruder,\nand click <confirm> for start loading." +#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_FR "Heat completed,please \nclick <confirm> for start unloading.!" +#define FILAMENT_DIALOG_LOADING_TIPS_FR "Is loading ,please wait!" +#define FILAMENT_DIALOG_UNLOADING_TIPS_FR "Is unloading,please wait!" +#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_FR "Load filament completed,\nclick <confirm> for return!" +#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_FR "Unload filament completed,\nclick <confirm> for return!" + + +#define PRE_HEAT_EXT_TEXT_FR "E" +#define PRE_HEAT_BED_TEXT_FR "Bed" + +#define FILE_LOADING_FR "Chargement......" +#define NO_FILE_AND_CHECK_FR "Aucun fichier,vérifiez à nouveau!" +#define NO_FILE_FR "Pas de fichier!" + +#define EXTRUDER_TEMP_TEXT_FR "Temper" +#define EXTRUDER_E_LENGTH1_TEXT_FR "Extruder1" +#define EXTRUDER_E_LENGTH2_TEXT_FR "Extruder2" +#define EXTRUDER_E_LENGTH3_TEXT_FR "Extruder3" + +#define ABOUT_TYPE_TEXT_FR "Type: " +#define ABOUT_VERSION_TEXT_FR "Firmware: " +#define ABOUT_WIFI_TEXT_FR "Wifi: " + +#define PRINTING_OPERATION_FR "Option" +#define PRINTING_PAUSE_FR "Pause" +#define PRINTING_TEMP_FR "Temp." +#define PRINTING_CHANGESPEED_FR "Speed" +#define PRINTING_RESUME_FR "Reprendre" +#define PRINTING_STOP_FR "Stop" +#define PRINTING_MORE_FR "Plus" +#define PRINTING_EXTRUDER_FR "Extruder" +#define PRINTING_MOVE_FR "Déplace" + +#define EXTRUDER_SPEED_FR "Extruder" +#define MOVE_SPEED_FR "Déplace" +#define EXTRUDER_SPEED_STATE_FR "Vitesse d'extrusion" +#define MOVE_SPEED_STATE_FR "vitesse de déplacement" +#define STEP_1PERCENT_FR "1%" +#define STEP_5PERCENT_FR "5%" +#define STEP_10PERCENT_FR "10%" + +#define TITLE_READYPRINT_FR "Prête" +#define TITLE_PREHEAT_FR "Préchauffe" +#define TITLE_MOVE_FR "Déplace" +#define TITLE_HOME_FR "Acceuil" +#define TITLE_EXTRUDE_FR "Extruder" +#define TITLE_LEVELING_FR "Leveling" +#define TITLE_SET_FR "Paramètres" +#define TITLE_MORE_FR "Plus" +#define TITLE_CHOOSEFILE_FR "Fichier" +#define TITLE_PRINTING_FR "Pimpression" +#define TITLE_OPERATION_FR "Option" +#define TITLE_ADJUST_FR "Réglage" +#define TITLE_WIRELESS_FR "Sans fil" +#define TITLE_FILAMENT_FR "Remplacer" +#define TITLE_ABOUT_FR "A propos" +#define TITLE_FAN_FR "Ventilateur" +#define TITLE_LANGUAGE_FR "Langue" +#define TITLE_PAUSE_FR "Pause" +#define TITLE_CHANGESPEED_FR "Speed" +#define TITLE_CLOUD_TEXT_FR "Cloud" +#define TITLE_DIALOG_CONFIRM_FR "Confirm" +#define TITLE_FILESYS_FR "FileSys" + +#define DIALOG_CLOSE_MACHINE_FR "Closing machine......" + +#define AUTO_SHUTDOWN_FR "Auto" +#define MANUAL_SHUTDOWN_FR "Manuel" + +#define DIALOG_CONFIRM_FR "Confirmer" +#define DIALOG_CANCLE_FR "Annuler" +#define DIALOG_OK_FR "OK" +#define DIALOG_RESET_FR "Réinitialiser" +#define DIALOG_RETRY_FR "Recommencez" +#define DIALOG_DISABLE_FR "Disable" +#define DIALOG_PRINT_MODEL_FR "Imprimer le fichier?" +#define DIALOG_CANCEL_PRINT_FR "Arrêter?" + +#define DIALOG_STOP_FR "Arrêter" +#define DIALOG_REPRINT_FROM_BREAKPOINT_FR "Continuer?" +#define DIALOG_ERROR_TIPS1_FR "Erreur:error:Aucun fichier, \nvérifiez à nouveau." +#define DIALOG_ERROR_TIPS2_FR "Erreur:La opération a échoué. \nVerifiez que le baudrate de l'écran et de \nla carte mère soient identique!" +#define DIALOG_ERROR_TIPS3_FR "Erreur: le nom du fichier ou le \nchemin d'accès est trop long." +#define DIALOG_UNBIND_PRINTER_FR "Unbind the printer?" +#define DIALOG_FILAMENT_NO_PRESS_FR "Filament detection switch is not pressed" +#define DIALOG_PRINT_FINISH_FR "L'impression est terminée!" +#define DIALOG_PRINT_TIME_FR "Temps d'impression: " +#define DIALOG_REPRINT_FR "Print again" +#define DIALOG_WIFI_ENABLE_TIPS_FR "The wifi module is being configured,\nplease wait a moment....." +#define DIALOG_PAUSING_TIPS_FR "La machine fait une pause ..." + +#define MESSAGE_PAUSING_FR "Parking..." +#define MESSAGE_CHANGING_FR "Attente filament pour démarrer" +#define MESSAGE_UNLOAD_FR "Attente retrait du filament" +#define MESSAGE_WAITING_FR "Presser bouton,pour reprendre" +#define MESSAGE_INSERT_FR "Insérer filament et app. bouton pour continuer..." +#define MESSAGE_LOAD_FR "Attente chargement filament" +#define MESSAGE_PURGE_FR "Attente Purge filament" +#define MESSAGE_RESUME_FR "Attente reprise impression" +#define MESSAGE_HEAT_FR "Presser le bouton pour chauffer..." +#define MESSAGE_HEATING_FR "Buse en chauffe Patienter SVP..." +#define MESSAGE_OPTION_FR "Purger davantage ou continuer l'impression?" +#define MESSAGE_PURGE_MORE_FR "Purge" +#define MESSAGE_CONTINUE_PRINT_FR "Impression" +#define EEPROM_SETTINGS_TITLE_FR "Paramètres EEPROM" +#define EEPROM_SETTINGS_STORE_FR "Stocker les paramètres dans l'EEPROM" +#define EEPROM_SETTINGS_READ_FR "Lire les paramètres de l'EEPROM" +#define EEPROM_SETTINGS_REVERT_FR "Rétablir les paramètres par défaut d'usine" + +#define EEPROM_STORE_TIPS_FR "Stocker les paramètres dans l'EEPROM?" +#define EEPROM_READ_TIPS_FR "Lire les paramètres de l'EEPROM?" +#define EEPROM_REVERT_TIPS_FR "Rétablir les paramètres par défaut d'usine?" + +#define MORE_CUSTOM1_TEXT_FR USER_DESC_1 +#define MORE_CUSTOM2_TEXT_FR USER_DESC_2 +#define MORE_CUSTOM3_TEXT_FR USER_DESC_3 +#define MORE_CUSTOM4_TEXT_FR USER_DESC_4 +#define MORE_CUSTOM5_TEXT_FR USER_DESC_5 +#define MORE_CUSTOM6_TEXT_FR USER_DESC_6 +#define MORE_CUSTOM7_TEXT_FR USER_DESC_7 diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_it.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_it.h new file mode 100644 index 0000000..2820feb --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_it.h @@ -0,0 +1,265 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +//****************意大利语***************************// +#define TOOL_TEXT_IT "Strumento" +#define PREHEAT_TEXT_IT "Prerisc" +#define MOVE_TEXT_IT "Muovi" +#define HOME_TEXT_IT "Home" +#define PRINT_TEXT_IT "Stampa" +#define EXTRUDE_TEXT_IT "Estrude" +#define LEVELING_TEXT_IT "Leveling" +#define AUTO_LEVELING_TEXT_IT "AutoLevel" +#define SET_TEXT_IT "Imposta" +#define MORE_TEXT_IT "Di più" + +#define ADD_TEXT_IT "Aumentare" +#define DEC_TEXT_IT "Ridurre" +#define EXTRUDER_1_TEXT_IT "Estrude1" +#define EXTRUDER_2_TEXT_IT "Estrude2" +#define HEATBED_TEXT_IT "Piano" +#define TEXT_1C_IT "1℃" +#define TEXT_5C_IT "5℃" +#define TEXT_10C_IT "10℃" +#define CLOSE_TEXT_IT "Spento" + +#define BACK_TEXT_IT "Indietro" + +#define TOOL_PREHEAT_IT "Prerisc" +#define TOOL_EXTRUDE_IT "Estrude" +#define TOOL_MOVE_IT "Muovi" +#define TOOL_HOME_IT "Home" +#define TOOL_LEVELING_IT "Leveling" +#define TOOL_AUTO_LEVELING_IT "Autolevel" +#define TOOL_FILAMENT_IT "Filamento" +#define TOOL_MORE_IT "Di più" + +#define AXIS_X_ADD_TEXT_IT "X+" +#define AXIS_X_DEC_TEXT_IT "X-" +#define AXIS_Y_ADD_TEXT_IT "Y+" +#define AXIS_Y_DEC_TEXT_IT "Y-" +#define AXIS_Z_ADD_TEXT_IT "Z+" +#define AXIS_Z_DEC_TEXT_IT "Z-" +#define TEXT_01MM_IT "0.1mm" +#define TEXT_1MM_IT "1mm" +#define TEXT_10MM_IT "10mm" + +#define HOME_X_TEXT_IT "X" +#define HOME_Y_TEXT_IT "Y" +#define HOME_Z_TEXT_IT "Z" +#define HOME_ALL_TEXT_IT "All" +#define HOME_STOPMOVE_IT "Quickstop" + +#define PAGE_UP_TEXT_IT "Pagina su" +#define PAGE_DOWN_TEXT_IT "Pagina giù" + +#define EXTRUDER_IN_TEXT_IT "Estru" +#define EXTRUDER_OUT_TEXT_IT "Ritra" +#define EXTRUDE_1MM_TEXT_IT "1mm" +#define EXTRUDE_5MM_TEXT_IT "5mm" +#define EXTRUDE_10MM_TEXT_IT "10mm" +#define EXTRUDE_LOW_SPEED_TEXT_IT "Bassa" +#define EXTRUDE_MEDIUM_SPEED_TEXT_IT "Media" +#define EXTRUDE_HIGH_SPEED_TEXT_IT "Alta" + +#define LEVELING_POINT1_TEXT_IT "Primo" +#define LEVELING_POINT2_TEXT_IT "Secondo" +#define LEVELING_POINT3_TEXT_IT "Terzo" +#define LEVELING_POINT4_TEXT_IT "Quarto" +#define LEVELING_POINT5_TEXT_IT "Quinto" + +#define FILESYS_TEXT_IT "FileSys" +#define WIFI_TEXT_IT "WIFI" +#define FAN_TEXT_IT "Ventola" +#define ABOUT_TEXT_IT "Circa" +#define BREAK_POINT_TEXT_IT "Continua" +#define FILAMENT_TEXT_IT "Filamento" +#define LANGUAGE_TEXT_IT "Lingua" +#define MOTOR_OFF_TEXT_IT "Motor off" +#define MOTOR_OFF_XY_TEXT_IT "Off-XY" +#define SHUTDOWN_TEXT_IT "Spento" +#define MACHINE_PARA_IT "Config" +#define EEPROM_SETTINGS_IT "Eeprom Set" + +#define U_DISK_TEXT_IT "USB" +#define SD_CARD_TEXT_IT "SD" +#define WIFI_NAME_TEXT_IT "WIFI: " +#define WIFI_KEY_TEXT_IT "KEY: " +#define WIFI_IP_TEXT_IT "IP: " +#define WIFI_AP_TEXT_IT "Stato: AP" +#define WIFI_STA_TEXT_IT "Stato: STA" +#define WIFI_CONNECTED_TEXT_IT "Connesso" +#define WIFI_DISCONNECTED_TEXT_IT "Disconnesso" +#define WIFI_EXCEPTION_TEXT_IT "Eccezione" +#define WIFI_RECONNECT_TEXT_IT "Reconnect" +#define CLOUD_TEXT_IT "Cloud" +#define CLOUD_BIND_IT "Legato" +#define CLOUD_UNBIND_IT "Libero" +#define CLOUD_DISCONNECTED_IT "Disconnesso" +#define CLOUD_UNBINDING_IT "Libero" +#define CLOUD_UNBINDED_IT "Sciolto" +#define CLOUD_BINDED_IT "Legato" +#define CLOUD_DISABLE_IT "Disable" + +#define FAN_ADD_TEXT_IT "Aumentare" +#define FAN_DEC_TEXT_IT "Ridurre" +#define FAN_OPEN_TEXT_IT "100%" +#define FAN_HALF_TEXT_IT "50%" +#define FAN_CLOSE_TEXT_IT "Spento" +#define FAN_TIPS1_TEXT_IT "Ventola" +#define FAN_TIPS2_TEXT_IT "Ventola\n0" + +#define FILAMENT_IN_TEXT_IT "Inser" +#define FILAMENT_OUT_TEXT_IT "Estra" +#define FILAMENT_EXT0_TEXT_IT "Estrude1" +#define FILAMENT_EXT1_TEXT_IT "Estrude2" +#define FILAMENT_HEAT_TEXT_IT "Preriscaldamento" +#define FILAMENT_STOP_TEXT_IT "Stop" +#define FILAMENT_TIPS2_TEXT_IT "T:" +#define FILAMENT_TIPS3_TEXT_IT "Inserimento del filamento..." +#define FILAMENT_TIPS4_TEXT_IT "Estrazione del filamento..." +#define FILAMENT_TIPS5_TEXT_IT "Temp is too low to go,please heat" +#define FILAMENT_TIPS6_TEXT_IT "Completato" + +#define FILAMENT_CHANGE_TEXT_IT "Please click <Load> \nor <unload>,After \npinter pause." +#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_IT "Heating up the nozzle,please wait..." +#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_IT "Heating up the nozzle,please wait..." +#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_IT "Heat completed,please load filament \nto extruder,and click <confirm> \nfor start loading." +#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_IT "Please load filament to extruder,\nand click <confirm> for start loading." +#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_IT "Heat completed,please \nclick <confirm> for start unloading.!" +#define FILAMENT_DIALOG_LOADING_TIPS_IT "Is loading ,please wait!" +#define FILAMENT_DIALOG_UNLOADING_TIPS_IT "Is unloading,please wait!" +#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_IT "Load filament completed,\nclick <confirm> for return!" +#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_IT "Unload filament completed,\nclick <confirm> for return!" + +#define PRE_HEAT_EXT_TEXT_IT "E" +#define PRE_HEAT_BED_TEXT_IT "Piano" + +#define FILE_LOADING_IT "Caricamento......" +#define NO_FILE_AND_CHECK_IT "Nessun file,\n per favore controllare di nuovo!" +#define NO_FILE_IT "Nessun file!" + +#define EXTRUDER_TEMP_TEXT_IT "Temper" +#define EXTRUDER_E_LENGTH1_TEXT_IT "Estrude1" +#define EXTRUDER_E_LENGTH2_TEXT_IT "Estrude2" +#define EXTRUDER_E_LENGTH3_TEXT_IT "Estrude3" + +#define ABOUT_TYPE_TEXT_IT "Type: " +#define ABOUT_VERSION_TEXT_IT "Firmware: " +#define ABOUT_WIFI_TEXT_IT "WiFi: " + +#define PRINTING_OPERATION_IT "Opzioni" +#define PRINTING_PAUSE_IT "Pause" +#define PRINTING_TEMP_IT "Temp." +#define PRINTING_CHANGESPEED_IT "Velocità" +#define PRINTING_RESUME_IT "Recupero" +#define PRINTING_STOP_IT "Stop" +#define PRINTING_MORE_IT "Di più" +#define PRINTING_EXTRUDER_IT "Estrude" +#define PRINTING_MOVE_IT "Muovi" + +#define EXTRUDER_SPEED_IT "Estrude" +#define MOVE_SPEED_IT "Muovi" +#define EXTRUDER_SPEED_STATE_IT "Estrusione" +#define MOVE_SPEED_STATE_IT "Movimento" +#define STEP_1PERCENT_IT "1%" +#define STEP_5PERCENT_IT "5%" +#define STEP_10PERCENT_IT "10%" + +#define TITLE_READYPRINT_IT "Pronto" +#define TITLE_PREHEAT_IT "Preris" +#define TITLE_MOVE_IT "Muovi" +#define TITLE_HOME_IT "Home" +#define TITLE_EXTRUDE_IT "Estrude" +#define TITLE_LEVELING_IT "Livella" +#define TITLE_SET_IT "Impostare" +#define TITLE_MORE_IT "Di più" +#define TITLE_CHOOSEFILE_IT "File" +#define TITLE_PRINTING_IT "Stampa" +#define TITLE_OPERATION_IT "Opzioni" +#define TITLE_ADJUST_IT "Regolare" +#define TITLE_WIRELESS_IT "Wireless" +#define TITLE_FILAMENT_IT "Filamento" +#define TITLE_ABOUT_IT "Circa" +#define TITLE_FAN_IT "Ventola" +#define TITLE_LANGUAGE_IT "Lingua" +#define TITLE_PAUSE_IT "Pausa" +#define TITLE_CHANGESPEED_IT "Velocità" +#define TITLE_CLOUD_TEXT_IT "Cloud" +#define TITLE_DIALOG_CONFIRM_IT "Confirm" +#define TITLE_FILESYS_IT "FileSys" + +#define AUTO_SHUTDOWN_IT "Auto" +#define MANUAL_SHUTDOWN_IT "Manuale" + +#define DIALOG_CONFIRM_IT "Conferma" +#define DIALOG_CANCLE_IT "Cancella" +#define DIALOG_OK_IT "OK" +#define DIALOG_RESET_IT "Resettare" +#define DIALOG_RETRY_IT "Riprovare" +#define DIALOG_DISABLE_IT "Disable" +#define DIALOG_PRINT_MODEL_IT "Gcode stampa?" +#define DIALOG_CANCEL_PRINT_IT "Stop stampa?" +#define DIALOG_STOP_IT "Stop" +#define DIALOG_REPRINT_FROM_BREAKPOINT_IT "Continua a stampare dal \npunto di interruzione?" +#define DIALOG_ERROR_TIPS1_IT "Errore: nessun file, \nper favore controllare di nuovo." +#define DIALOG_ERROR_TIPS2_IT "Errore: operazione non riuscita, \nsi prega di controllare se il baudrate del \ndisplay è lo stesso scheda madre" +#define DIALOG_ERROR_TIPS3_IT "Errore: il nome del file o il \npercorso è troppo lungo!" +#define DIALOG_CLOSE_MACHINE_IT "Closing machine......" +#define DIALOG_UNBIND_PRINTER_IT "Unbind the printer?" +#define DIALOG_FILAMENT_NO_PRESS_IT "Filament detection switch is not pressed" +#define DIALOG_PRINT_FINISH_IT "La stampa è completa!" +#define DIALOG_PRINT_TIME_IT "Tempo di stampa: " +#define DIALOG_REPRINT_IT "Print again" +#define DIALOG_WIFI_ENABLE_TIPS_IT "The wifi module is being configured,\nplease wait a moment....." +#define DIALOG_PAUSING_TIPS_IT "La macchina si ferma ..." + +#define MESSAGE_PAUSING_IT "Parcheggiando..." +#define MESSAGE_CHANGING_IT "Attendere avvio del cambio di filamento" +#define MESSAGE_UNLOAD_IT "Attendere l'espulsione del filamento" +#define MESSAGE_WAITING_IT "Premi per riprendere la stampa" +#define MESSAGE_INSERT_IT "Inserisci il filamento e premi per continuare" +#define MESSAGE_LOAD_IT "Attendere il caricamento del filamento" +#define MESSAGE_PURGE_IT "Attendere lo spurgo del filamento" +#define MESSAGE_RESUME_IT "Attendere la ripresa della stampa..." +#define MESSAGE_HEAT_IT "Premi per riscaldare ugello" +#define MESSAGE_HEATING_IT "Riscaldam. ugello Attendere prego..." +#define MESSAGE_OPTION_IT "Eliminare di più o continuare a stampare?" +#define MESSAGE_PURGE_MORE_IT "Epurazione" +#define MESSAGE_CONTINUE_PRINT_IT "Stampa" +#define EEPROM_SETTINGS_TITLE_IT "Impostazioni EEPROM" +#define EEPROM_SETTINGS_STORE_IT "Memorizzare le impostazioni su EEPROM" +#define EEPROM_SETTINGS_READ_IT "Leggi le impostazioni dalla EEPROM" +#define EEPROM_SETTINGS_REVERT_IT "Ripristina le impostazioni predefinite di fabbrica" + +#define EEPROM_STORE_TIPS_IT "Memorizzare le impostazioni su EEPROM?" +#define EEPROM_READ_TIPS_IT "Leggi le impostazioni dalla EEPROM?" +#define EEPROM_REVERT_TIPS_IT "Ripristinare le impostazioni predefinite?" + +#define MORE_CUSTOM1_TEXT_IT USER_DESC_1 +#define MORE_CUSTOM2_TEXT_IT USER_DESC_2 +#define MORE_CUSTOM3_TEXT_IT USER_DESC_3 +#define MORE_CUSTOM4_TEXT_IT USER_DESC_4 +#define MORE_CUSTOM5_TEXT_IT USER_DESC_5 +#define MORE_CUSTOM6_TEXT_IT USER_DESC_6 +#define MORE_CUSTOM7_TEXT_IT USER_DESC_7 diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_ru.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_ru.h new file mode 100644 index 0000000..04fbf25 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_ru.h @@ -0,0 +1,384 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +//****************俄语***************************// +#define TOOL_TEXT_RU "инструмент" +#define PREHEAT_TEXT_RU " нагрев" +#define MOVE_TEXT_RU "движение" +#define HOME_TEXT_RU "домой" +#define PRINT_TEXT_RU " печать" +#define EXTRUDE_TEXT_RU "экструзия" +#define LEVELING_TEXT_RU "уровень" +#define AUTO_LEVELING_TEXT_RU "aвтоуровень" +#define SET_TEXT_RU "настройки" +#define MORE_TEXT_RU "больше" + +#define ADD_TEXT_RU "добавить" +#define DEC_TEXT_RU "уменьшить" +#define EXTRUDER_1_TEXT_RU "экструдер1" +#define EXTRUDER_2_TEXT_RU "экструдер2" +#define HEATBED_TEXT_RU "стол" +#define TEXT_1C_RU "1℃" +#define TEXT_5C_RU "5℃" +#define TEXT_10C_RU "10℃" +#define CLOSE_TEXT_RU "выкл" + +#define BACK_TEXT_RU "назад" + +#define TOOL_PREHEAT_RU "нагрев" +#define TOOL_EXTRUDE_RU "экструдер" +#define TOOL_MOVE_RU "движение" +#define TOOL_HOME_RU "домой" +#define TOOL_LEVELING_RU "уровень" +#define TOOL_AUTO_LEVELING_RU "aвтоуровень" +#define TOOL_FILAMENT_RU "замена" +#define TOOL_MORE_RU "больше" + +#define AXIS_X_ADD_TEXT_RU "X +" +#define AXIS_X_DEC_TEXT_RU "X -" +#define AXIS_Y_ADD_TEXT_RU "Y +" +#define AXIS_Y_DEC_TEXT_RU "Y -" +#define AXIS_Z_ADD_TEXT_RU "Z +" +#define AXIS_Z_DEC_TEXT_RU "Z -" +#define TEXT_01MM_RU "0.1 mm" +#define TEXT_1MM_RU "1 mm" +#define TEXT_10MM_RU "10 mm" + +#define HOME_X_TEXT_RU "X" +#define HOME_Y_TEXT_RU "Y" +#define HOME_Z_TEXT_RU "Z" +#define HOME_ALL_TEXT_RU "Home" +#define HOME_STOPMOVE_RU "Quickstop" + +#define PAGE_UP_TEXT_RU "вверх" +#define PAGE_DOWN_TEXT_RU "вниз" + +#define EXTRUDER_IN_TEXT_RU "втянуть" +#define EXTRUDER_OUT_TEXT_RU "выдавить" +#define EXTRUDE_1MM_TEXT_RU "1 mm" +#define EXTRUDE_5MM_TEXT_RU "5 mm" +#define EXTRUDE_10MM_TEXT_RU "10 mm" +#define EXTRUDE_LOW_SPEED_TEXT_RU "мин" +#define EXTRUDE_MEDIUM_SPEED_TEXT_RU "сред" +#define EXTRUDE_HIGH_SPEED_TEXT_RU "выс" + +#define LEVELING_POINT1_TEXT_RU "1 точка" +#define LEVELING_POINT2_TEXT_RU "2 точка" +#define LEVELING_POINT3_TEXT_RU "3 точка" +#define LEVELING_POINT4_TEXT_RU "4 точка" +#define LEVELING_POINT5_TEXT_RU "5 точка" + +#define FILESYS_TEXT_RU "система" +#define WIFI_TEXT_RU "WiFi" +#define FAN_TEXT_RU "вентилятор" +#define ABOUT_TEXT_RU "инфо" +#define BREAK_POINT_TEXT_RU "продолжить" +#define FILAMENT_TEXT_RU "замена" +#define LANGUAGE_TEXT_RU "язык" +#define MOTOR_OFF_TEXT_RU "откл. мотор" +#define MOTOR_OFF_XY_TEXT_RU "Off-XY" +#define SHUTDOWN_TEXT_RU "выключение" +#define MACHINE_PARA_RU "конфиг" + +#define U_DISK_TEXT_RU "U диск" +#define SD_CARD_TEXT_RU "SD диск" +#define WIFI_NAME_TEXT_RU "WiFi: " +#define WIFI_KEY_TEXT_RU "пароль: " +#define WIFI_IP_TEXT_RU "IP: " +#define WIFI_AP_TEXT_RU "режим: AP" +#define WIFI_STA_TEXT_RU "режим: STA" +#define WIFI_CONNECTED_TEXT_RU "подключен" +#define WIFI_DISCONNECTED_TEXT_RU "не подключен" +#define WIFI_EXCEPTION_TEXT_RU "исключение" +#define WIFI_RECONNECT_TEXT_RU "выбор сети" +#define CLOUD_TEXT_RU "облако" +#define CLOUD_BIND_RU "соединён" +#define CLOUD_UNBIND_RU "отсоед." +#define CLOUD_UNBINDING_RU "отвязано" +#define CLOUD_DISCONNECTED_RU "отключено" +#define CLOUD_UNBINDED_RU "несвяз." +#define CLOUD_BINDED_RU "связано" +#define CLOUD_DISABLE_RU "Disable" + +#define FAN_ADD_TEXT_RU "добавить" +#define FAN_DEC_TEXT_RU "уменьшить" +#define FAN_OPEN_TEXT_RU "100%" +#define FAN_HALF_TEXT_RU "50%" +#define FAN_CLOSE_TEXT_RU "откл" +#define FAN_TIPS1_TEXT_RU "вентилятор" +#define FAN_TIPS2_TEXT_RU "вентилятор\nоткл" + +#define FILAMENT_IN_TEXT_RU "втянуть" +#define FILAMENT_OUT_TEXT_RU "выдавить" +#define FILAMENT_EXT0_TEXT_RU "экструдер1" +#define FILAMENT_EXT1_TEXT_RU "экструдер2" +#define FILAMENT_HEAT_TEXT_RU "нагрев" +#define FILAMENT_STOP_TEXT_RU "стоп" +#define FILAMENT_TIPS2_TEXT_RU "T:" +#define FILAMENT_TIPS3_TEXT_RU "втянуть..." +#define FILAMENT_TIPS4_TEXT_RU "вядавить..." +#define FILAMENT_TIPS5_TEXT_RU "Низкая температура, \nнеобходим нагрев" +#define FILAMENT_TIPS6_TEXT_RU "завершено" + +#define FILAMENT_CHANGE_TEXT_RU "Please click <Load> \nor <unload>,After \npinter pause." +#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_RU "Heating up the nozzle,\nplease wait..." +#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_RU "Heating up the nozzle,\nplease wait..." +#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_RU "Heat completed,please load filament \nto extruder,and click <confirm> \nfor start loading." +#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_RU "Please load filament to extruder,\nand click <confirm> for start loading." +#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_RU "Heat completed,please \nclick <confirm> for start unloading.!" +#define FILAMENT_DIALOG_LOADING_TIPS_RU "Is loading ,please wait!" +#define FILAMENT_DIALOG_UNLOADING_TIPS_RU "Is unloading,please wait!" +#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_RU "Load filament completed,\nclick <confirm> for return!" +#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_RU "Unload filament completed,\nclick <confirm> for return!" + +#define PRE_HEAT_EXT_TEXT_RU "E" +#define PRE_HEAT_BED_TEXT_RU "стол" + +#define FILE_LOADING_RU "загрузка......" +#define NO_FILE_AND_CHECK_RU "нет файла,попробуйте ещё раз!" + +#define NO_FILE_RU "нет файла!" + +#define EXTRUDER_TEMP_TEXT_RU "температура" +#define EXTRUDER_E_LENGTH1_TEXT_RU "экструзия1" +#define EXTRUDER_E_LENGTH2_TEXT_RU "экструзия2" +#define EXTRUDER_E_LENGTH3_TEXT_RU "экструзия3" + +#define ABOUT_TYPE_TEXT_RU "Type: " +#define ABOUT_VERSION_TEXT_RU "Firmware: " +#define ABOUT_WIFI_TEXT_RU "WiFi: " + +#define PRINTING_OPERATION_RU "опции" +#define PRINTING_PAUSE_RU "пауза" +#define PRINTING_TEMP_RU "темп" +#define PRINTING_CHANGESPEED_RU "скорости" +#define PRINTING_RESUME_RU "возобн. " +#define PRINTING_STOP_RU "стоп" +#define PRINTING_MORE_RU "больше" +#define PRINTING_EXTRUDER_RU "экстр" +#define PRINTING_MOVE_RU "движение" + +#define EXTRUDER_SPEED_RU "экстр" +#define MOVE_SPEED_RU "движ" +#define EXTRUDER_SPEED_STATE_RU "скорость экстр" +#define MOVE_SPEED_STATE_RU "скорость движ" +#define STEP_1PERCENT_RU "1%" +#define STEP_5PERCENT_RU "5%" +#define STEP_10PERCENT_RU "10%" + +#define TITLE_READYPRINT_RU "готов к" +#define TITLE_PREHEAT_RU "движение" +#define TITLE_MOVE_RU "движение" +#define TITLE_HOME_RU "Home" +#define TITLE_EXTRUDE_RU "экструзия" +#define TITLE_LEVELING_RU "уровень" +#define TITLE_MLEVELING_RU "углы" +#define TITLE_SET_RU "настройки" +#define TITLE_MORE_RU "больше" +#define TITLE_CHOOSEFILE_RU "файла" +#define TITLE_PRINTING_RU "печать" +#define TITLE_OPERATION_RU "управление" +#define TITLE_ADJUST_RU "регулировать" +#define TITLE_WIRELESS_RU "Wireless" +#define TITLE_FILAMENT_RU "замена" +#define TITLE_ABOUT_RU "инфо" +#define TITLE_FAN_RU "вентилятор" +#define TITLE_LANGUAGE_RU "язык" +#define TITLE_PAUSE_RU "пауза" +#define TITLE_CHANGESPEED_RU "скорости" +#define TILE_TOOL_RU "инструмент" +#define TITLE_CLOUD_TEXT_RU "Cloud" +#define TITLE_DIALOG_CONFIRM_RU "Confirm" +#define TITLE_FILESYS_RU "FileSys" + +#define AUTO_SHUTDOWN_RU "авто-откл" +#define MANUAL_SHUTDOWN_RU "ручн-откл" + +#define DIALOG_CONFIRM_RU "да"//"подтвердить" +#define DIALOG_CANCLE_RU "отмена" +#define DIALOG_OK_RU "да" +#define DIALOG_RESET_RU "сброс" +#define DIALOG_RETRY_RU "повтор" +#define DIALOG_DISABLE_RU "запретить" +#define DIALOG_PRINT_MODEL_RU "печать модели?" +#define DIALOG_CANCEL_PRINT_RU "стоп?" +#define DIALOG_STOP_RU "стоп" +#define DIALOG_REPRINT_FROM_BREAKPOINT_RU "продолжить?" +#define DIALOG_ERROR_TIPS1_RU "ошибка:нет файла, попробуйте ещё раз." +#define DIALOG_ERROR_TIPS2_RU "ошибка:сбой передачи. установите скорость \nпередачи данных как на плате управления!" +#define DIALOG_ERROR_TIPS3_RU "ошибка: имя файла слишком длинное!" +#define DIALOG_CLOSE_MACHINE_RU "Closing machine......" +#define DIALOG_UNBIND_PRINTER_RU "Unbind the printer?" +#define DIALOG_FILAMENT_NO_PRESS_RU "Filament detection switch is not pressed" +#define DIALOG_PRINT_FINISH_RU "печать завершена!" +#define DIALOG_PRINT_TIME_RU "Время печати: " +#define DIALOG_REPRINT_RU "Print again" +#define DIALOG_WIFI_ENABLE_TIPS_RU "The wifi module is being configured,\nplease wait a moment....." +#define DIALOG_PAUSING_TIPS_RU "Машина останавливается ..." + +#define MESSAGE_PAUSING_RU "Стоянка..." +#define MESSAGE_CHANGING_RU "Подождите, пока начнется смена филамента" +#define MESSAGE_UNLOAD_RU "Дождитесь выгрузки нити" +#define MESSAGE_WAITING_RU "Нажмите кнопку,чтобы возобновить печать" +#define MESSAGE_INSERT_RU "Вставьте нить и нажмите кнопку,чтобы продолжить" +#define MESSAGE_LOAD_RU "Дождитесь загрузки нити" +#define MESSAGE_PURGE_RU "Дождитесь чистки нити" +#define MESSAGE_RESUME_RU "Подождите,пока печать возобновится ..." +#define MESSAGE_HEAT_RU "Нажмите кнопку, чтобы нагреть форсунку" +#define MESSAGE_HEATING_RU "Подогрев форсунки Пожалуйста, подождите ..." +#define MESSAGE_OPTION_RU "Очистить больше или продолжить печать?" +#define MESSAGE_PURGE_MORE_RU "чистка" +#define MESSAGE_CONTINUE_PRINT_RU "Распечатать" +#define EEPROM_SETTINGS_TITLE_RU "Настройки EEPROM" +#define EEPROM_SETTINGS_STORE_RU "Cохранение настроек в EEPROM" +#define EEPROM_SETTINGS_READ_RU "Чтение настроек из EEPROM" +#define EEPROM_SETTINGS_REVERT_RU "Bосстановить заводские настройки по умолчанию" + +#define MORE_CUSTOM1_TEXT_RU USER_DESC_1 +#define MORE_CUSTOM2_TEXT_RU USER_DESC_2 +#define MORE_CUSTOM3_TEXT_RU USER_DESC_3 +#define MORE_CUSTOM4_TEXT_RU USER_DESC_4 +#define MORE_CUSTOM5_TEXT_RU USER_DESC_5 +#define MORE_CUSTOM6_TEXT_RU USER_DESC_6 +#define MORE_CUSTOM7_TEXT_RU USER_DESC_7 + +//Malderin translate +// +// +#define EEPROM_STORE_TIPS_RU "Cохранить настройки в EEPROM?" +#define EEPROM_READ_TIPS_RU "читать настройки из EEPROM?" +#define EEPROM_REVERT_TIPS_RU "Cбросить настройки к значениям по умолчанию?" +#define EEPROM_SETTINGS_RU "EEPROM" + + +#define NEXT_RU "след." +#define PREVIOUS_RU "пред." +#define ENABLE_RU "да " +#define DISABLE_RU "нет" +#define KEY_CONFIRM_RU "OK" + +#define MACHINE_PARA_TITLE_RU "настройки" +#define MACHINE_TYPE_CNOFIG_RU "Hастройки принтера" +#define MOTOR_CONFIG_RU "Hастройки моторов" +#define MACHINE_LEVELING_CONFIG_RU "Hастройки уровня" +#define ADVANCE_CONFIG_RU "Pасширенные настройки" +#define MACHINE_FILAMENT_CONFIG_RU "Hастройки филамента" +#define ENCODER_SETTINGS_RU "Hастройки энкодера" + + +#define LEVELING_CONF_TITLE_RU "Hастройки принтера>Hастройки уровня" +#define LEVELING_PARA_CONF_RU "настройки уровня" +#define LEVELING_MANUAL_POS_RU "настройки координат для уровня" +#define LEVELING_AUTO_COMMAND_RU "настройки комманд увтоуровня" +#define LEVELING_AUTO_ZOFFSET_RU "координаты смещения сопла" +#define LEVELING_TOUCHMI_RU "Settings-TouchMi-Probe" +#define TM_INIT_RU "Init" +#define TM_ZOFFSETPOS_RU "Zoffset+" +#define TM_ZOFFSETNEG_RU "Zoffset-" +#define TM_SAVE_RU "Save" +#define TM_TEST_RU "Test" + +#define BLTOUCH_LEVELING_TITTLE_RU "Settings>BL-Touch Probe" +#define BLTOUCH_LEVELING_RU "BL-Touch Probe" +#define BLTOUCH_INIT_RU "Init" +#define BLTOUCH_ZOFFSETPOS_RU "Zoffset+" +#define BLTOUCH_ZOFFSETNEG_RU "Zoffset-" +#define BLTOUCH_SAVE_RU "Save" +#define BLTOUCH_TEST_RU "Test" + +#define MACHINE_CONFIG_TITLE_RU "Hастройки принтера>настройки притера" +#define MAXFEEDRATE_CONF_RU "настройки максимальной скорости" +#define ACCELERATION_CONF_RU "настройки ускорений" +#define JERKCONF_RU "настройки рывков" + +#define MOTOR_CONF_TITLE_RU "Hастройки принтера>Hастройки моторов" +#define STEPSCONF_RU "настройки шагов" +#define TMC_CURRENT_RU "TMC настройки токов" +#define TMC_STEP_MODE_RU "TMC настрйоки режима шагов" + +#define ACCELERATION_CONF_TITLE_RU "Hастройки принтера>ускорения" +#define PRINT_ACCELERATION_RU "ускорение печати" +#define RETRACT_ACCELERATION_RU "ускорение ретракта" +#define TRAVEL_ACCELERATION_RU "ускорение перемещений" +#define X_ACCELERATION_RU "ускорение оси X" +#define Y_ACCELERATION_RU "ускорение оси Y" +#define Z_ACCELERATION_RU "ускорение оси Z" +#define E0_ACCELERATION_RU "ускорение E0" +#define E1_ACCELERATION_RU "ускорение E1" + +#define MAXFEEDRATE_CONF_TITLE_RU "Hастройки принтера>максимальная скорость" +#define X_MAXFEEDRATE_RU "максимальная скорость оси X" +#define Y_MAXFEEDRATE_RU "максимальная скорость оси Y" +#define Z_MAXFEEDRATE_RU "максимальная скорость оси Z" +#define E0_MAXFEEDRATE_RU "максимальная скорость E0" +#define E1_MAXFEEDRATE_RU "максимальная скорость E1" + +#define JERK_CONF_TITLE_RU "Hастройки принтера>скорость рывка" +#define X_JERK_RU "скорость рывка оси X" +#define Y_JERK_RU "скорость рывка оси Y" +#define Z_JERK_RU "скорость рывка оси Z" +#define E_JERK_RU "скорость рывка оси E" + +#define STEPS_CONF_TITLE_RU "Hастройки принтера>настройки шагов" +#define X_STEPS_RU "шаги оси X" +#define Y_STEPS_RU "шаги оси Y" +#define Z_STEPS_RU "шаги оси Z" +#define E0_STEPS_RU "шаги E0" +#define E1_STEPS_RU "шаги E1" + +#define TMC_CURRENT_CONF_TITLE_RU "Hастройки принтера>TMC настройка токов" +#define X_TMC_CURRENT_RU "ток оси X (mA)" +#define Y_TMC_CURRENT_RU "ток оси Y (mA)" +#define Z_TMC_CURRENT_RU "ток оси Z (mA)" +#define E0_TMC_CURRENT_RU "ток E0 (mA)" +#define E1_TMC_CURRENT_RU "ток E1 (mA)" + +#define TMC_MODE_CONF_TITLE_RU "Hастройки принтера>TMC настройки режима шагов" +#define X_TMC_MODE_RU "включает ли двигатель X режим StealthChop" +#define Y_TMC_MODE_RU "включает ли ось Y режим StealthChop" +#define Z_TMC_MODE_RU "включает ли ось Z режим StealthChop" +#define E0_TMC_MODE_RU "включает ли E0 режим StealthChop" +#define E1_TMC_MODE_RU "включает ли E1 режим StealthChop" + +#define ADVANCED_CONF_TITLE_RU "Hастройки принтера>Pасширенные" +#define PAUSE_POSITION_RU "Hастройки позиции паузы печати" +#define PAUSE_POSITION_X_RU "положение по X (абс. полож., -1 недействит.)" +#define PAUSE_POSITION_Y_RU "положение по Y (абс. полож., -1 недействит.)" +#define PAUSE_POSITION_Z_RU "положение по Z (абс. полож., -1 недействит.)" + +#define OFFSET_TITLE_RU "Hастройки принтера>отступ" +#define OFFSET_X_RU "X отступ" +#define OFFSET_Y_RU "Y отступ" +#define OFFSET_Z_RU "Z отступ" + +#define FILAMENT_CONF_TITLE_RU "Hастройки принтера>Hастройки филамента" +#define FILAMENT_IN_LENGTH_RU "длинна загрузки" +#define FILAMENT_IN_SPEED_RU "скорость загрузки" +#define FILAMENT_TEMPERATURE_RU "температура филамента" +#define FILAMENT_OUT_LENGTH_RU "длинна извлечения" +#define FILAMENT_OUT_SPEED_RU "скорость извлечения" + +#define ENCODER_CONF_TITLE_RU "Hастройки принтера>Hастройки энкодера" +#define ENCODER_CONF_TEXT_RU "энкодер используется?" + +//end of Malderin translate diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_s_cn.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_s_cn.h new file mode 100644 index 0000000..4623749 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_s_cn.h @@ -0,0 +1,518 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +//*************简体中文***********************// +#define NEXT_CN "下一页" +#define PREVIOUS_CN "上一页" +#define DEFAULT_CN "默认值" +#define KEY_BACK_CN "退格" +#define KEY_REST_CN "重置" +#define KEY_CONFIRM_CN "确定" + +#define MACHINE_PARA_TITLE_CN "机器参数" +#define MACHINE_TYPE_CNOFIG_CN "机器设置" +#define MOTOR_CONFIG_CN "电机设置" +#define MACHINE_LEVELING_CONFIG_CN "调平设置" +#define ADVANCE_CONFIG_CN "高级设置" + +#define MACHINE_CONFIG_TITLE_CN "机器参数>机器配置" +#define MACHINE_TYPE_CN "机型选择" +#define MACHINE_STROKE_CN "行程设置" +#define MACHINE_HOMEDIR_CN "归零方向" +#define MACHINE_ENDSTOP_TYPE_CN "限位开关类型" +#define MACHINE_FILAMENT_CONFIG_CN "换料设置" + +#define MACHINE_TYPE_CONFIG_TITLE_CN "机器参数>机型选择" +#define MACHINE_TYPE_XYZ_CN "XYZ机型" +#define MACHINE_TYPE_DELTA_CN "Delta机型" +#define MACHINE_TYPE_COREXY_CN "Corexy机型" + +#define MACHINE_STROKE_CONF_TITLE_CN "机器参数>机器行程" +#define X_MAX_LENGTH_CN "X轴最大行程" +#define Y_MAX_LENGTH_CN "Y轴最大行程" +#define Z_MAX_LENGTH_CN "Z轴最大行程" + +#define X_MIN_LENGTH_CN "X轴最小行程" +#define Y_MIN_LENGTH_CN "Y轴最小行程" +#define Z_MIN_LENGTH_CN "Z轴最小行程" + +#define HOME_DIR_CONF_TITLE_CN "机器参数>归零方向" +#define HOME_DIR_X_CN "X轴归零方向" +#define HOME_DIR_Y_CN "Y轴归零方向" +#define HOME_DIR_Z_CN "Z轴归零方向" +#define HOME_MIN_CN "MIN" +#define HOME_MAX_CN "MAX" + +#define ENDSTOP_CONF_TITLE_CN "机器参数>限位开关" +#define MIN_ENDSTOP_X_CN "X轴最小限位" +#define MIN_ENDSTOP_Y_CN "Y轴最小限位" +#define MIN_ENDSTOP_Z_CN "Z轴最小限位" +#define MAX_ENDSTOP_X_CN "X轴最大限位" +#define MAX_ENDSTOP_Y_CN "Y轴最大限位" +#define MAX_ENDSTOP_Z_CN "Z轴最大限位" +#define ENDSTOP_FIL_CN "断料开关类型" +#define ENDSTOP_LEVEL_CN "调平开关类型" +#define ENDSTOP_OPENED_CN "常开" +#define ENDSTOP_CLOSED_CN "常闭" + +#define FILAMENT_CONF_TITLE_CN "换料设置" +#define FILAMENT_IN_LENGTH_CN "进料长度" +#define FILAMENT_IN_SPEED_CN "进料速度" +#define FILAMENT_TEMPERATURE_CN "换料温度" +#define FILAMENT_OUT_LENGTH_CN "退料长度" +#define FILAMENT_OUT_SPEED_CN "退料速度" + +#define LEVELING_CONF_TITLE_CN "机器参数>调平设置" +#define LEVELING_PARA_CONF_CN "调平设置" +#define LEVELING_MANUAL_POS_CN "手动调平坐标设置" +#define LEVELING_AUTO_COMMAND_CN "自动调平指令设置" +#define LEVELING_AUTO_ZOFFSET_CN "挤出头与调平开关偏移设置" + +#define BLTOUCH_LEVELING_TITTLE_CN "机器参数>BL-Touch Probe" +#define BLTOUCH_LEVELING_CN "BL-Touch Probe" +#define BLTOUCH_INIT_CN "初始化" +#define BLTOUCH_ZOFFSETPOS_CN "Zoffset+" +#define BLTOUCH_ZOFFSETNEG_CN "Zoffset-" +#define BLTOUCH_SAVE_CN "保存" +#define BLTOUCH_TEST_CN "测试" + +#define LEVELING_TOUCHMI_CN "机器参数>TouchMi-Probe" +#define TM_INIT_CN "初始化" +#define TM_ZOFFSETPOS_CN "Zoffset+" +#define TM_ZOFFSETNEG_CN "Zoffset-" +#define TM_SAVE_CN "保存" +#define TM_TEST_CN "测试" + +#define LEVELING_PARA_CONF_TITLE_CN "调平参数" +#define AUTO_LEVELING_ENABLE_CN "自动调平" +#define BLTOUCH_LEVELING_ENABLE_CN "启动BLtouch" +#define PROBE_PORT_CN "调平探针接口" +#define PROBE_X_OFFSET_CN "探针X方向偏移" +#define PROBE_Y_OFFSET_CN "探针Y方向偏移" +#define PROBE_Z_OFFSET_CN "探针Z方向偏移" +#define PROBE_XY_SPEED_CN "探针XY方向移动速度" +#define PROBE_Z_SPEED_CN "探针Z方向移动速度" +#define ENABLE_CN "是" +#define DISABLE_CN "否" +#define LOCKED_CN "否" +#define Z_MIN_CN "ZMin" +#define Z_MAX_CN "ZMax" + +#define DELTA_LEVEL_CONF_TITLE_CN "Delta机器参数" +#define DELTA_LEVEL_CONF_CN "Delta机器调平" +#define DELTA_MACHINE_RADIUS_CN "机器半径" +#define DELTA_DIAGONAL_ROD_CN "机器杆长" +#define DELTA_PRINT_RADIUS_CN "打印半径" +#define DELTA_HEIGHT_CN "打印高度" +#define SMOOTH_ROD_OFFSET_CN "滑块偏移" +#define EFFECTOR_OFFSET_CN "效应器偏移" +#define CALIBRATION_RADIUS_CN "调平半径" + +#define XYZ_LEVEL_CONF_TITLE_CN "XYZ机器参数" +#define PROBE_REACH_MAX_LEFT_CN "探针达到最左位置" +#define PROBE_REACH_MAX_RIGHT_CN "探针达到最右位置" +#define PROBE_REACH_MAX_FRONT_CN "探针达到最前位置" +#define PROBE_REACH_MAX_BACK_CN "探针达到最后位置" + +#define TEMPERATURE_CONF_TITLE_CN "机器参数>温度设置" +#define NOZZLE_CONF_CN "喷头设置" +#define HOTBED_CONF_CN "热床设置" +#define PREHEAT_TEMPER_CN "预设温度" + +#define NOZZLE_CONF_TITLE_CN "机器参数>喷头设置" +#define NOZZLECNT_CN "喷头数量" +#define NOZZLE_TYPE_CN "E0温感类型" +#define NOZZLE_ADJUST_TYPE_CN "PID调温" +#define NOZZLE_MIN_TEMPERATURE_CN "最低温度" +#define NOZZLE_MAX_TEMPERATURE_CN "最高温度" +#define EXTRUD_MIN_TEMPER_CN "最低挤出温度" + +#define HOTBED_CONF_TITLE_CN "机器参数>热床设置" +#define HOTBED_ADJUST_CN "PID调温" +#define HOTBED_MIN_TEMPERATURE_CN "最低温度" +#define HOTBED_MAX_TEMPERATURE_CN "最高温度" + +#define MOTOR_CONF_TITLE_CN "机器参数>电机设置" +#define MAXFEEDRATE_CONF_CN "最大速度设置" +#define ACCELERATION_CONF_CN "加速度设置" +#define JERKCONF_CN "突变速度设置" +#define STEPSCONF_CN "脉冲设置" +#define TMC_CURRENT_CN "TMC 驱动电流设置" +#define TMC_STEP_MODE_CN "TMC 驱动模式设置" +#define MOTORDIRCONF_CN "电机方向设置" +#define HOMEFEEDRATECONF_CN "归零速度设置" +#define HOMING_SENSITIVITY_CONF_CN "无限位回零灵敏度调节" + +#define MAXFEEDRATE_CONF_TITLE_CN "机器参数>最大速度" +#define X_MAXFEEDRATE_CN "X轴最大速度" +#define Y_MAXFEEDRATE_CN "Y轴最大速度" +#define Z_MAXFEEDRATE_CN "Z轴最大速度" +#define E0_MAXFEEDRATE_CN "E0轴最大速度" +#define E1_MAXFEEDRATE_CN "E1轴最大速度" + +#define ACCELERATION_CONF_TITLE_CN "机器参数>加速度" +#define PRINT_ACCELERATION_CN "打印加速度" +#define RETRACT_ACCELERATION_CN "回抽加速度" +#define TRAVEL_ACCELERATION_CN "空载加速度" +#define X_ACCELERATION_CN "X轴加速度" +#define Y_ACCELERATION_CN "Y轴加速度" +#define Z_ACCELERATION_CN "Z轴加速度" +#define E0_ACCELERATION_CN "E0轴加速度" +#define E1_ACCELERATION_CN "E1轴加速度" + +#define JERK_CONF_TITLE_CN "机器参数>突变速度" +#define X_JERK_CN "X轴突变速度" +#define Y_JERK_CN "Y轴突变速度" +#define Z_JERK_CN "Z轴突变速度" +#define E_JERK_CN "E轴突变速度" + +#define STEPS_CONF_TITLE_CN "机器参数>脉冲设置" +#define X_STEPS_CN "X轴脉冲" +#define Y_STEPS_CN "Y轴脉冲" +#define Z_STEPS_CN "Z轴脉冲" +#define E0_STEPS_CN "E0轴脉冲" +#define E1_STEPS_CN "E1轴脉冲" + +#define TMC_CURRENT_CONF_TITLE_CN "机器参数>TMC电流设置" +#define X_TMC_CURRENT_CN "X轴电流(毫安)" +#define Y_TMC_CURRENT_CN "Y轴电流(毫安)" +#define Z_TMC_CURRENT_CN "Z轴电流(毫安)" +#define E0_TMC_CURRENT_CN "E0轴电流(毫安)" +#define E1_TMC_CURRENT_CN "E1轴电流(毫安)" + +#define TMC_MODE_CONF_TITLE_CN "机器参数>TMC模式设置" +#define X_TMC_MODE_CN "X轴是否使能静音模式" +#define Y_TMC_MODE_CN "Y轴是否使能静音模式" +#define Z_TMC_MODE_CN "Z轴是否使能静音模式" +#define E0_TMC_MODE_CN "E0轴是否使能静音模式" +#define E1_TMC_MODE_CN "E1轴是否使能静音模式" + +#define MOTORDIR_CONF_TITLE_CN "机器参数>电机方向" +#define X_MOTORDIR_CN "X轴电机方向" +#define Y_MOTORDIR_CN "Y轴电机方向" +#define Z_MOTORDIR_CN "Z轴电机方向" +#define E0_MOTORDIR_CN "E0轴电机方向" +#define E1_MOTORDIR_CN "E1轴电机方向" +#define INVERT_P_CN "正向" +#define INVERT_N_CN "反向" + +#define HOMEFEEDRATE_CONF_TITLE_CN "机器参数>归零速度" +#define X_HOMESPEED_CN "XY轴归零速度" +#define Y_HOMESPEED_CN "Y轴归零速度" +#define Z_HOMESPEED_CN "Z轴归零速度" + +#define ADVANCED_CONF_TITLE_CN "机器参数>高级设置" +#define PWROFF_DECTION_CN "断电检测模块" +#define PWROFF_AFTER_PRINT_CN "启动打完关机功能" +#define HAVE_UPS_CN "机器配备UPS电源" +#define Z2_AND_Z2ENDSTOP_CONF_CN "双Z轴双限位功能设置" +#define ENABLE_PINS_CONF_CN "电机使能脚电平设置" +#define WIFI_SETTINGS_CN "Wi-Fi参数设置" +#define ENCODER_SETTINGS_CN "旋钮设置" + +#define Z2_AND_Z2ENDSTOP_CONF_TITLE_CN "双z双限位设置" +#define Z2_ENABLE_CN "启用Z2轴" +#define Z2_ENDSTOP_CN "启用Z2限位" +#define Z2_PORT_CN "Z2限位接口" + +#define ENABLE_PINS_CONF_TITLE_CN "电机使能脚电平" +#define X_ENABLE_PINS_INVERT_CN "X轴电机使能电平" +#define Y_ENABLE_PINS_INVERT_CN "Y轴电机使能电平" +#define Z_ENABLE_PINS_INVERT_CN "Z轴电机使能电平" +#define E_ENABLE_PINS_INVERT_CN "E轴电机使能电平" + +#define PAUSE_POSITION_CN "打印暂停位置设置" +#define PAUSE_POSITION_X_CN "X轴暂停位置(绝对位置,-1无效)" +#define PAUSE_POSITION_Y_CN "Y轴暂停位置(绝对位置,-1无效)" +#define PAUSE_POSITION_Z_CN "Z轴暂停位置(相对位置,-1无效)" +#define WIFI_SETTINGS_TITLE_CN "机器参数>Wi-Fi设置" +#define WIFI_SETTINGS_MODE_CN "Wi-Fi 模式" +#define WIFI_SETTINGS_NAME_CN "Wi-Fi 名称: " +#define WIFI_SETTINGS_PASSWORD_CN "Wi-Fi 密码: " +#define WIFI_SETTINGS_CLOUD_CN "是否使用云服务?" +#define WIFI_SETTINGS_CONFIG_CN "配置" +#define WIFI_SETTINGS_EDIT_CN "编辑" +#define WIFI_CONFIG_TIPS_CN "进行Wi-Fi配置?" + +#define OFFSET_TITLE_CN "机器参数>偏移设置" +#define OFFSET_X_CN "X轴与调平开关偏移" +#define OFFSET_Y_CN "Y轴与调平开关偏移" +#define OFFSET_Z_CN "Z轴与调平开关偏移" + +#define HOMING_SENSITIVITY_CONF_TITLE_CN "机器参数>灵敏度调节" +#define X_SENSITIVITY_CN "X轴灵敏度" +#define Y_SENSITIVITY_CN "Y轴灵敏度" +#define Z_SENSITIVITY_CN "Z轴灵敏度" +#define Z2_SENSITIVITY_CN "Z2轴灵敏度" + +#define ENCODER_CONF_TITLE_CN "机器参数>旋钮设置" +#define ENCODER_CONF_TEXT_CN "是否使用旋钮功能?" + +#define TOOL_TEXT_CN "工具" +#define PREHEAT_TEXT_CN "预热" +#define MOVE_TEXT_CN "移动" +#define HOME_TEXT_CN "回零" +#define PRINT_TEXT_CN "打印" +#define EXTRUDE_TEXT_CN "挤出" +#define LEVELING_TEXT_CN "调平" +#define AUTO_LEVELING_TEXT_CN "自动调平" +#define SET_TEXT_CN "设置" +#define MORE_TEXT_CN "更多" + +#define ADD_TEXT_CN "增加" +#define DEC_TEXT_CN "减少" +#define EXTRUDER_1_TEXT_CN "喷头1" +#define EXTRUDER_2_TEXT_CN "喷头2" +#define HEATBED_TEXT_CN "热床" +#define TEXT_1C_CN "1℃" +#define TEXT_5C_CN "5℃" +#define TEXT_10C_CN "10℃" +#define CLOSE_TEXT_CN "关闭" + +#define BACK_TEXT_CN "返回" + +#define TOOL_PREHEAT_CN "预热" +#define TOOL_EXTRUDE_CN "挤出" +#define TOOL_MOVE_CN "移动" +#define TOOL_HOME_CN "回零" +#define TOOL_LEVELING_CN "调平" +#define TOOL_AUTO_LEVELING_CN "自动调平" +#define TOOL_FILAMENT_CN "换料" +#define TOOL_MORE_CN "更多" + +#define AXIS_X_ADD_TEXT_CN "X+" +#define AXIS_X_DEC_TEXT_CN "X-" +#define AXIS_Y_ADD_TEXT_CN "Y+" +#define AXIS_Y_DEC_TEXT_CN "Y-" +#define AXIS_Z_ADD_TEXT_CN "Z+" +#define AXIS_Z_DEC_TEXT_CN "Z-" +#define TEXT_01MM_CN "0.1mm" +#define TEXT_1MM_CN "1mm" +#define TEXT_10MM_CN "10mm" + +#define HOME_X_TEXT_CN "X" +#define HOME_Y_TEXT_CN "Y" +#define HOME_Z_TEXT_CN "Z" +#define HOME_ALL_TEXT_CN "回零" +#define HOME_STOPMOVE_CN "急停" + +#define PAGE_UP_TEXT_CN "上一页" +#define PAGE_DOWN_TEXT_CN "下一页" + +#define EXTRUDER_IN_TEXT_CN "进料" +#define EXTRUDER_OUT_TEXT_CN "退料" +#define EXTRUDE_1MM_TEXT_CN "1mm" +#define EXTRUDE_5MM_TEXT_CN "5mm" +#define EXTRUDE_10MM_TEXT_CN "10mm" +#define EXTRUDE_LOW_SPEED_TEXT_CN "低速" +#define EXTRUDE_MEDIUM_SPEED_TEXT_CN "常速" +#define EXTRUDE_HIGH_SPEED_TEXT_CN "高速" + +#define LEVELING_POINT1_TEXT_CN "第一点" +#define LEVELING_POINT2_TEXT_CN "第二点" +#define LEVELING_POINT3_TEXT_CN "第三点" +#define LEVELING_POINT4_TEXT_CN "第四点" +#define LEVELING_POINT5_TEXT_CN "第五点" + +#define FILESYS_TEXT_CN "文件系统" +#define WIFI_TEXT_CN "WIFI" +#define FAN_TEXT_CN "风扇" +#define ABOUT_TEXT_CN "关于" +#define BREAK_POINT_TEXT_CN "断点续打" +#define FILAMENT_TEXT_CN "换料" +#define LANGUAGE_TEXT_CN "语言" +#define MOTOR_OFF_TEXT_CN "关闭电机" +#define MOTOR_OFF_XY_TEXT_CN "关闭XY" +#define SHUTDOWN_TEXT_CN "关机" +#define MACHINE_PARA_CN "机器参数" +#define EEPROM_SETTINGS_CN "Eeprom设置" + +#define U_DISK_TEXT_CN "U盘" +#define SD_CARD_TEXT_CN "SD卡" +#define WIFI_NAME_TEXT_CN "无线网络:" +#define WIFI_KEY_TEXT_CN "密码: " +#define WIFI_IP_TEXT_CN "IP: " +#define WIFI_AP_TEXT_CN "状态: AP" +#define WIFI_STA_TEXT_CN "状态: STA" +#define WIFI_CONNECTED_TEXT_CN "已连接" +#define WIFI_DISCONNECTED_TEXT_CN "未连接" +#define WIFI_EXCEPTION_TEXT_CN "模块异常" +#define CLOUD_TEXT_CN "云服务" +#define CLOUD_BIND_CN "已绑定" +#define CLOUD_UNBIND_CN "解绑" +#define CLOUD_UNBINDING_CN "解绑中" +#define CLOUD_DISCONNECTED_CN "未连接" +#define CLOUD_UNBINDED_CN "未绑定" +#define CLOUD_BINDED_CN "已绑定" +#define CLOUD_DISABLE_CN "已禁用" + +#define FAN_ADD_TEXT_CN "增加" +#define FAN_DEC_TEXT_CN "减少" +#define FAN_OPEN_TEXT_CN "100%" +#define FAN_HALF_TEXT_CN "50%" +#define FAN_CLOSE_TEXT_CN "关闭" +#define FAN_TIPS1_TEXT_CN "风扇" +#define FAN_TIPS2_TEXT_CN "FAN\nClose" + +#define FILAMENT_IN_TEXT_CN "进料" +#define FILAMENT_OUT_TEXT_CN "退料" +#define FILAMENT_EXT0_TEXT_CN "喷头1" +#define FILAMENT_EXT1_TEXT_CN "喷头2" +#define FILAMENT_HEAT_TEXT_CN "预热" +#define FILAMENT_STOP_TEXT_CN "停止" +#define FILAMENT_CHANGE_TEXT_CN "待打印机暂停后,\n请按<进料>或<退料>" + +#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_CN "准备进料,正在加热,请稍等!" +#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_CN "准备退料,正在加热,请稍等!" +#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_CN "加热完成,请装载耗材后,按<确定>开始进料!" +#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_CN "请装载耗材,按<确定>开始进料!" +#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_CN "加热完成,请按<确定>开始退料!" +#define FILAMENT_DIALOG_LOADING_TIPS_CN "正在进料,请等待耗材加载完成!" +#define FILAMENT_DIALOG_UNLOADING_TIPS_CN "正在退料,请等待耗材卸载完成!" +#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_CN "进料完成,请按<确定>返回" +#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_CN "退料完成,请按<确定>返回" + +#define FILAMENT_TIPS3_TEXT_CN "正在进料" +#define FILAMENT_TIPS4_TEXT_CN "正在退料" +#define FILAMENT_TIPS5_TEXT_CN "温度太低,请先预热" +#define FILAMENT_TIPS6_TEXT_CN "换料完成" + +#define PRE_HEAT_EXT_TEXT_CN "喷头" +#define PRE_HEAT_BED_TEXT_CN "热床" + +#define FILE_LOADING_CN "正在载入......" +#define NO_FILE_AND_CHECK_CN "无文件!请插入sd卡或u盘!" +#define NO_FILE_CN "无文件!" + +#define EXTRUDER_TEMP_TEXT_CN "温度" +#define EXTRUDER_E_LENGTH1_TEXT_CN "喷头" +#define EXTRUDER_E_LENGTH2_TEXT_CN "喷头" +#define EXTRUDER_E_LENGTH3_TEXT_CN "喷头" + +#define ABOUT_TYPE_TEXT_CN "Type: " +#define ABOUT_VERSION_TEXT_CN "Firmware: " +#define ABOUT_WIFI_TEXT_CN "Wifi: " + +#define PRINTING_OPERATION_CN "操作" +#define PRINTING_PAUSE_CN "暂停" +#define PRINTING_TEMP_CN "温度" +#define PRINTING_CHANGESPEED_CN "变速" +#define PRINTING_RESUME_CN "恢复" +#define PRINTING_STOP_CN "停止" +#define PRINTING_MORE_CN "更多" +#define PRINTING_EXTRUDER_CN "挤出" +#define PRINTING_MOVE_CN "移动" + +#define EXTRUDER_SPEED_CN "挤出" +#define MOVE_SPEED_CN "移动" +#define EXTRUDER_SPEED_STATE_CN "挤出速度" +#define MOVE_SPEED_STATE_CN "移动速度" +#define STEP_1PERCENT_CN "1%" +#define STEP_5PERCENT_CN "5%" +#define STEP_10PERCENT_CN "10%" + +#define TITLE_READYPRINT_CN "准备打印" +#define TITLE_PREHEAT_CN "预热" +#define TITLE_MOVE_CN "移动" +#define TITLE_HOME_CN "回零" +#define TITLE_EXTRUDE_CN "挤出" +#define TITLE_LEVELING_CN "调平" +#define TITLE_SET_CN "设置" +#define TITLE_MORE_CN "更多" +#define TITLE_CHOOSEFILE_CN "选择文件" +#define TITLE_PRINTING_CN "正在打印" +#define TITLE_OPERATION_CN "操作" +#define TITLE_ADJUST_CN "调整" +#define TITLE_WIRELESS_CN "无线网络" +#define TITLE_FILAMENT_CN "换料" +#define TITLE_ABOUT_CN "关于" +#define TITLE_FAN_CN "风扇" +#define TITLE_LANGUAGE_CN "语言" +#define TITLE_PAUSE_CN "暂停" +#define TITLE_CHANGESPEED_CN "变速" +#define TITLE_CLOUD_TEXT_CN "云服务" +#define TITLE_DIALOG_CONFIRM_CN "确认" +#define TITLE_FILESYS_CN "文件系统" + +#define AUTO_SHUTDOWN_CN "自动关机" +#define MANUAL_SHUTDOWN_CN "手动关机" + +#define DIALOG_CONFIRM_CN "确定" +#define DIALOG_CANCLE_CN "取消" +#define DIALOG_OK_CN "确认" +#define DIALOG_RESET_CN "重置" +#define DIALOG_DISABLE_CN "禁用" +#define DIALOG_PRINT_MODEL_CN "打印模型?" +#define DIALOG_CANCEL_PRINT_CN "停止打印?" +#define DIALOG_RETRY_CN "重试" +#define DIALOG_STOP_CN "停止" +#define DIALOG_REPRINT_FROM_BREAKPOINT_CN "从断点续打?" +#define DIALOG_ERROR_TIPS1_CN "错误:找不到文件,请插入sd卡/u盘!" +#define DIALOG_ERROR_TIPS2_CN "错误:通信失败,请检查波特率或主板硬件!" +#define DIALOG_ERROR_TIPS3_CN "错误:文件名或文件路径太长 !" +#define DIALOG_CLOSE_MACHINE_CN "正在关机......" +#define DIALOG_UNBIND_PRINTER_CN "解除绑定?" +#define DIALOG_FILAMENT_NO_PRESS_CN "请先装载耗材!" +#define DIALOG_PRINT_FINISH_CN "打印完成!" +#define DIALOG_PRINT_TIME_CN "打印时间: " +#define DIALOG_REPRINT_CN "再打印一次" +#define DIALOG_WIFI_ENABLE_TIPS_CN "wifi模块正在配置中,请稍等......" +#define DIALOG_PAUSING_TIPS_CN "机器暂停中..." + +#define TEXT_VALUE_CN "%d℃/%d℃" +#define EXTRUDE_TEXT_VALUE_T_CN ": %d℃" +#define WIFI_RECONNECT_TEXT_CN "重新连接" + +#define PRINTING_GBK "正在打印" +#define PRINTING_OPERATION_GBK "操作" +#define PRINTING_PAUSE_GBK "暂停" + +#define MESSAGE_PAUSING_CN "暂停中..." +#define MESSAGE_CHANGING_CN "等待换料开始..." +#define MESSAGE_UNLOAD_CN "退料中,请稍等..." +#define MESSAGE_WAITING_CN "点击按钮恢复打印" +#define MESSAGE_INSERT_CN "装载耗材后,点击按钮开始打印" +#define MESSAGE_LOAD_CN "进料中,请稍等..." +#define MESSAGE_PURGE_CN "等待挤出..." +#define MESSAGE_RESUME_CN "等待恢复打印..." +#define MESSAGE_HEAT_CN "按下按钮,加热喷头" +#define MESSAGE_HEATING_CN "喷头加热中,请等待..." +#define MESSAGE_OPTION_CN "挤出更多还是继续打印?" +#define MESSAGE_PURGE_MORE_CN "挤出" +#define MESSAGE_CONTINUE_PRINT_CN "打印" +#define EEPROM_SETTINGS_TITLE_CN "EEPROM 设置" +#define EEPROM_SETTINGS_STORE_CN "保存参数至EEPROM" +#define EEPROM_SETTINGS_READ_CN "读取EEPROM参数" +#define EEPROM_SETTINGS_REVERT_CN "恢复默认参数" + +#define EEPROM_STORE_TIPS_CN "是否保存参数到EEPROM?" +#define EEPROM_READ_TIPS_CN "是否使用EEPROM参数?" +#define EEPROM_REVERT_TIPS_CN "是否恢复默认参数?" + +#define MORE_CUSTOM1_TEXT_CN USER_DESC_1 +#define MORE_CUSTOM2_TEXT_CN USER_DESC_2 +#define MORE_CUSTOM3_TEXT_CN USER_DESC_3 +#define MORE_CUSTOM4_TEXT_CN USER_DESC_4 +#define MORE_CUSTOM5_TEXT_CN USER_DESC_5 +#define MORE_CUSTOM6_TEXT_CN USER_DESC_6 +#define MORE_CUSTOM7_TEXT_CN USER_DESC_7 diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_sp.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_sp.h new file mode 100644 index 0000000..675af55 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_sp.h @@ -0,0 +1,274 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +//****************西班牙语*************************** +#define TOOL_TEXT_SP "Ajustes" +#define PREHEAT_TEXT_SP "Precalentar" +#define MOVE_TEXT_SP "Mover" +#define HOME_TEXT_SP "Origen" +#define PRINT_TEXT_SP "Imprimir" +#define EXTRUDE_TEXT_SP "Extrusor" +#define LEVELING_TEXT_SP "Leveling" +#define MLEVELING_TEXT_SP "Leveling" +#define AUTO_LEVELING_TEXT_SP "Autolevel" +#define SET_TEXT_SP "Config" +#define MORE_TEXT_SP "Más" + +#define ADD_TEXT_SP "Más" +#define DEC_TEXT_SP "Menos" +#define EXTRUDER_1_TEXT_SP "Extrusor1: " +#define EXTRUDER_2_TEXT_SP "Extrusor2: " +#define HEATBED_TEXT_SP "Cama: " +#define TEXT_1C_SP "1℃" +#define TEXT_5C_SP "5℃" +#define TEXT_10C_SP "10℃" +#define CLOSE_TEXT_SP "Apagar" + +#define BACK_TEXT_SP "Atrás" + +#define TOOL_PREHEAT_SP "Precalentar" +#define TOOL_EXTRUDE_SP "Extrusor" +#define TOOL_MOVE_SP "Mover" +#define TOOL_HOME_SP "Origen" +#define TOOL_LEVELING_SP "Leveling" +#define TOOL_MLEVELING_SP "Leveling" +#define TOOL_AUTO_LEVELING_SP "Autolevel" +#define TOOL_FILAMENT_SP "Filamento" +#define TOOL_MORE_SP "Más" + +#define AXIS_X_ADD_TEXT_SP "X+" +#define AXIS_X_DEC_TEXT_SP "X-" +#define AXIS_Y_ADD_TEXT_SP "Y+" +#define AXIS_Y_DEC_TEXT_SP "Y-" +#define AXIS_Z_ADD_TEXT_SP "Z+" +#define AXIS_Z_DEC_TEXT_SP "Z-" +#define TEXT_01MM_SP "0.1mm" +#define TEXT_1MM_SP "1mm" +#define TEXT_10MM_SP "10mm" + +#define HOME_X_TEXT_SP "EJE X" +#define HOME_Y_TEXT_SP "EJE Y" +#define HOME_Z_TEXT_SP "EJE Z" +#define HOME_ALL_TEXT_SP "TODOS" +#define HOME_STOPMOVE_SP "Quickstop" + +#define PAGE_UP_TEXT_SP "Arriba" +#define PAGE_DOWN_TEXT_SP "Abajo" + +#define EXTRUDER_IN_TEXT_SP "Dentro" +#define EXTRUDER_OUT_TEXT_SP "Fuera" +#define EXTRUDE_1MM_TEXT_SP "1mm" +#define EXTRUDE_5MM_TEXT_SP "5mm" +#define EXTRUDE_10MM_TEXT_SP "10mm" +#define EXTRUDE_LOW_SPEED_TEXT_SP "Baja" +#define EXTRUDE_MEDIUM_SPEED_TEXT_SP "Media" +#define EXTRUDE_HIGH_SPEED_TEXT_SP "Alta" + +#define LEVELING_POINT1_TEXT_SP "Primero" +#define LEVELING_POINT2_TEXT_SP "Segundo" +#define LEVELING_POINT3_TEXT_SP "Tercero" +#define LEVELING_POINT4_TEXT_SP "Cuarto" +#define LEVELING_POINT5_TEXT_SP "Quinto" + +#define FILESYS_TEXT_SP "Puerto" +#define WIFI_TEXT_SP "WiFi" +#define FAN_TEXT_SP "Ventilador" +#define ABOUT_TEXT_SP "Acerca" +#define BREAK_POINT_TEXT_SP "Continuar" +#define FILAMENT_TEXT_SP "Filamento" +#define LANGUAGE_TEXT_SP "Language" +#define MOTOR_OFF_TEXT_SP "Apagar motor" +#define MOTOR_OFF_XY_TEXT_SP "Off-XY" +#define SHUTDOWN_TEXT_SP "Apagar" +#define MACHINE_PARA_SP "Config" +#define EEPROM_SETTINGS_SP "Eeprom Set" + +#define U_DISK_TEXT_SP "PENDRIVE" +#define SD_CARD_TEXT_SP "SD" +#define WIFI_NAME_TEXT_SP "WIFI: " +#define WIFI_KEY_TEXT_SP "Contraseña: " +#define WIFI_IP_TEXT_SP "IP: " +#define WIFI_AP_TEXT_SP "Estado: AP" +#define WIFI_STA_TEXT_SP "Estado: STA" +#define WIFI_CONNECTED_TEXT_SP "Conectado" +#define WIFI_DISCONNECTED_TEXT_SP "Desconectado" +#define WIFI_EXCEPTION_TEXT_SP "Excepción" +#define WIFI_RECONNECT_TEXT_SP "Reconnect" +#define CLOUD_TEXT_SP "Nube" +#define CLOUD_BIND_SP "Atado" +#define CLOUD_UNBIND_SP "Sin atar" +#define CLOUD_UNBINDING_SP "Unbinding" +#define CLOUD_DISCONNECTED_SP "Disconnected" +#define CLOUD_UNBINDED_SP "Unbinded" +#define CLOUD_BINDED_SP "Binded" +#define CLOUD_DISABLE_SP "Disable" + +#define FAN_ADD_TEXT_SP "Más" +#define FAN_DEC_TEXT_SP "Menos" +#define FAN_OPEN_TEXT_SP "100%" +#define FAN_HALF_TEXT_SP "50%" +#define FAN_CLOSE_TEXT_SP "0%" +#define FAN_TIPS1_TEXT_SP "ventilador" +#define FAN_TIPS2_TEXT_SP "ventilador\n0" + +#define FILAMENT_IN_TEXT_SP "Dentro" +#define FILAMENT_OUT_TEXT_SP "Fuera" +#define FILAMENT_EXT0_TEXT_SP "Extrusor1" +#define FILAMENT_EXT1_TEXT_SP "Extrusor2" +#define FILAMENT_HEAT_TEXT_SP "Precalentar" +#define FILAMENT_STOP_TEXT_SP "Parar" +#define FILAMENT_TIPS2_TEXT_SP "T:" +#define FILAMENT_TIPS3_TEXT_SP "Dentro..." +#define FILAMENT_TIPS4_TEXT_SP "Fuera..." +#define FILAMENT_TIPS5_TEXT_SP "Temperatura demasiado baja, por favor calentar" +#define FILAMENT_TIPS6_TEXT_SP "Completado" + +#define FILAMENT_CHANGE_TEXT_SP "Please click <Load> \nor <unload>,After \npinter pause." +#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_SP "Calentando el extrusor,\npor favor espere..." +#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_SP "Calentando el extrusor,\npor favor espere..." +#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_SP "Temperatura alcanzada.Inserte el \nfilamento y luego presione\"Confirmar\"\npara comenzar la carga." +#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_SP "Inserte el filamento y \nluego presione\"Confirmar\"para \ncomenzar la carga." +#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_SP "Temperatura alcanzada.\nPresione\"Confirmar\"para retirar \nel filamento." +#define FILAMENT_DIALOG_LOADING_TIPS_SP "Cargando filamento,\npor favor espere." +#define FILAMENT_DIALOG_UNLOADING_TIPS_SP "Retirando filamento,\npor favor espere." +#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_SP "Filamento cargado,\npresione\"Confirmar\"." +#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_SP "Filamento retirado,\npresione\"Confirmar\"." + +#define PRE_HEAT_EXT_TEXT_SP "Extrusor" +#define PRE_HEAT_BED_TEXT_SP "cama" + +#define FILE_LOADING_SP "Cargando......" +#define NO_FILE_AND_CHECK_SP "Archivo no encontrado,\n por favor insertar SD o disco USB!" +#define NO_FILE_SP "Sin archivo!" + +#define EXTRUDER_TEMP_TEXT_SP "Temper" +#define EXTRUDER_E_LENGTH1_TEXT_SP "Extrusor1" +#define EXTRUDER_E_LENGTH2_TEXT_SP "Extrusor2" +#define EXTRUDER_E_LENGTH3_TEXT_SP "Extrusor3" + +#define ABOUT_TYPE_TEXT_SP "Pantalla: " +#define ABOUT_VERSION_TEXT_SP "Firmware: " +#define ABOUT_WIFI_TEXT_SP "WiFi: " + +#define PRINTING_OPERATION_SP "Ajustes" +#define PRINTING_PAUSE_SP "Pausar" +#define PRINTING_TEMP_SP "Temp." +#define PRINTING_CHANGESPEED_SP "Velocidad" +#define PRINTING_RESUME_SP "Resumir" +#define PRINTING_STOP_SP "Detener" +#define PRINTING_MORE_SP "Más" +#define PRINTING_EXTRUDER_SP "Extrusor" +#define PRINTING_MOVE_SP "Mover" + +#define EXTRUDER_SPEED_SP "Extrusor" +#define MOVE_SPEED_SP "Mover" +#define EXTRUDER_SPEED_STATE_SP "Extrusión" +#define MOVE_SPEED_STATE_SP "Movimiento" +#define STEP_1PERCENT_SP "1%" +#define STEP_5PERCENT_SP "5%" +#define STEP_10PERCENT_SP "10%" + +#define TITLE_READYPRINT_SP "Inicio" +#define TITLE_PREHEAT_SP "Precalentar" +#define TITLE_MOVE_SP "Mover" +#define TITLE_HOME_SP "Origen" +#define TITLE_EXTRUDE_SP "Extrusor" +#define TITLE_LEVELING_SP "Leveling" +#define TITLE_SET_SP "Config" +#define TITLE_MORE_SP "Más" +#define TITLE_CHOOSEFILE_SP "Imprimir" +#define TITLE_PRINTING_SP "Imprimir" +#define TITLE_OPERATION_SP "Ajustes" +#define TITLE_ADJUST_SP "Temp." +#define TITLE_WIRELESS_SP "Wireless" +#define TITLE_FILAMENT_SP "Filamento" +#define TITLE_ABOUT_SP "Acerca" +#define TITLE_FAN_SP "Ventilador" +#define TITLE_LANGUAGE_SP "Language" +#define TITLE_PAUSE_SP "Pausar" +#define TITLE_CHANGESPEED_SP "Velocidad" +#define TILE_TOOL_SP "Ajustes" +#define TITLE_CLOUD_TEXT_SP "Cloud" +#define TITLE_DIALOG_CONFIRM_SP "Confirmar" +#define TITLE_FILESYS_SP "Puerto" + +#define AUTO_SHUTDOWN_SP "Auto" +#define MANUAL_SHUTDOWN_SP "manual" + +#define DIALOG_CONFIRM_SP "Confirmar" +#define DIALOG_CANCLE_SP "Cancelar" +#define DIALOG_OK_SP "OK" +#define DIALOG_RESET_SP "Resetear" +#define DIALOG_RETRY_SP "Reintentar" +#define DIALOG_DISABLE_SP "Desactivar" +#define DIALOG_PRINT_MODEL_SP "¿Está seguro?" +#define DIALOG_CANCEL_PRINT_SP "¿Está seguro que desea detener la impresión?" + +#define DIALOG_RETRY_SP "Reintentar" +#define DIALOG_STOP_SP "Stop" +#define DIALOG_REPRINT_FROM_BREAKPOINT_SP "Reprint from breakpoint?" +#define DIALOG_ERROR_TIPS1_SP "Error:archivo no encontrado, \npor favor insertar SD o disco USB." +#define DIALOG_ERROR_TIPS2_SP "error:transacción fallida, \nconfigurar baudrate del \ndisplay para la placa base!" +#define DIALOG_ERROR_TIPS3_SP "Error : nombre de archivo o \nruta demasiado largo!" +#define DIALOG_CLOSE_MACHINE_SP "Closing machine......" +#define DIALOG_UNBIND_PRINTER_SP "Unbind the printer?" +#define DIALOG_FILAMENT_NO_PRESS_SP "Filament detection switch is not pressed" +#define DIALOG_PRINT_FINISH_SP "¡La impresión está completa!" +#define DIALOG_PRINT_TIME_SP "Tiempo de impresión: " +#define DIALOG_REPRINT_SP "Print again" +#define DIALOG_WIFI_ENABLE_TIPS_SP "The wifi module is being configured,\nplease wait a moment....." +#define DIALOG_PAUSING_TIPS_SP "La máquina se detiene ..." + +#define PRINTING_SP "Imprimiendo" +#define PRINTING_AJUSTES_SP "Ajustes" +#define PRINTING_PAUSAR_SP "Pausar" + +#define MESSAGE_PAUSING_SP "Aparcando..." +#define MESSAGE_CHANGING_SP "Esperando para iniciar el cambio de filamento" +#define MESSAGE_UNLOAD_SP "Espere para liberar el filamento" +#define MESSAGE_WAITING_SP "Pulsar el botón para reanudar impresión" +#define MESSAGE_INSERT_SP "Inserte el filamento y pulse el botón para continuar..." +#define MESSAGE_LOAD_SP "Espere para purgar el filamento" +#define MESSAGE_PURGE_SP "Espere para purgar el filamento" +#define MESSAGE_RESUME_SP "Esperando impresora para reanudar..." +#define MESSAGE_HEAT_SP "Pulse el botón para calentar la boquilla" +#define MESSAGE_HEATING_SP "Calentando boquilla Espere por favor..." +#define MESSAGE_OPTION_SP "¿Purgar más o continuar con la impresión?" +#define MESSAGE_PURGE_MORE_SP "Purga" +#define MESSAGE_CONTINUE_PRINT_SP "Impresión" +#define EEPROM_SETTINGS_TITLE_SP "Configuraciones EEPROM" +#define EEPROM_SETTINGS_STORE_SP "Guardar configuración en EEPROM" +#define EEPROM_SETTINGS_READ_SP "Leer la configuración de EEPROM" +#define EEPROM_SETTINGS_REVERT_SP "Revert settings to factory defaults" + +#define EEPROM_STORE_TIPS_SP "¿Guardar ajustes en EEPROM?" +#define EEPROM_READ_TIPS_SP "Leer la configuración de EEPROM?" +#define EEPROM_REVERT_TIPS_SP "Revert settings to factory defaults?" + +#define MORE_CUSTOM1_TEXT_SP USER_DESC_1 +#define MORE_CUSTOM2_TEXT_SP USER_DESC_2 +#define MORE_CUSTOM3_TEXT_SP USER_DESC_3 +#define MORE_CUSTOM4_TEXT_SP USER_DESC_4 +#define MORE_CUSTOM5_TEXT_SP USER_DESC_5 +#define MORE_CUSTOM6_TEXT_SP USER_DESC_6 +#define MORE_CUSTOM7_TEXT_SP USER_DESC_7 diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_t_cn.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_t_cn.h new file mode 100644 index 0000000..e97c63c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_Language_t_cn.h @@ -0,0 +1,515 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +//***************繁体中文**********************// +#define NEXT_T_CN "下一頁" +#define PREVIOUS_T_CN "上一頁" +#define DEFAULT_T_CN "默認值" +#define KEY_BACK_T_CN "退格" +#define KEY_REST_T_CN "重置" +#define KEY_CONFIRM_T_CN "確定" + +#define MACHINE_PARA_TITLE_T_CN "機器參數" +#define MACHINE_TYPE_CNOFIG_T_CN "機器設置" +#define MOTOR_CONFIG_T_CN "電機設置" +#define MACHINE_LEVELING_CONFIG_T_CN "調平設置" +#define ADVANCE_CONFIG_T_CN "高級設置" + +#define MACHINE_CONFIG_TITLE_T_CN "機器參數>機器配置" +#define MACHINE_TYPE_T_CN "機型選擇" +#define MACHINE_STROKE_T_CN "行程設置" +#define MACHINE_HOMEDIR_T_CN "歸零方向" +#define MACHINE_ENDSTOP_TYPE_T_CN "限位開關類型" +#define MACHINE_FILAMENT_CONFIG_T_CN "換料設置" + +#define MACHINE_TYPE_CONFIG_TITLE_T_CN "機器參數>機型選擇" +#define MACHINE_TYPE_XYZ_T_CN "XYZ機型" +#define MACHINE_TYPE_DELTA_T_CN "Delta機型" +#define MACHINE_TYPE_COREXY_T_CN "Corexy機型" + +#define MACHINE_STROKE_CONF_TITLE_T_CN "機器參數>機器行程" +#define X_MAX_LENGTH_T_CN "X軸最大行程" +#define Y_MAX_LENGTH_T_CN "Y軸最大行程" +#define Z_MAX_LENGTH_T_CN "Z軸最大行程" + +#define X_MIN_LENGTH_T_CN "X軸最小行程" +#define Y_MIN_LENGTH_T_CN "Y軸最小行程" +#define Z_MIN_LENGTH_T_CN "Z軸最小行程" + +#define HOME_DIR_CONF_TITLE_T_CN "機器參數>歸零方向" +#define HOME_DIR_X_T_CN "X軸歸零方向" +#define HOME_DIR_Y_T_CN "Y軸歸零方向" +#define HOME_DIR_Z_T_CN "Z軸歸零方向" +#define HOME_MIN_T_CN "MIN" +#define HOME_MAX_T_CN "MAX" + +#define ENDSTOP_CONF_TITLE_T_CN "機器參數>限位開關" +#define MIN_ENDSTOP_X_T_CN "X軸最小限位" +#define MIN_ENDSTOP_Y_T_CN "Y軸最小限位" +#define MIN_ENDSTOP_Z_T_CN "Z軸最小限位" +#define MAX_ENDSTOP_X_T_CN "X軸最大限位" +#define MAX_ENDSTOP_Y_T_CN "Y軸最大限位" +#define MAX_ENDSTOP_Z_T_CN "Z軸最大限位" +#define ENDSTOP_FIL_T_CN "斷料開關類型" +#define ENDSTOP_LEVEL_T_CN "調平開關類型" +#define ENDSTOP_OPENED_T_CN "常開" +#define ENDSTOP_CLOSED_T_CN "常閉" + +#define FILAMENT_CONF_TITLE_T_CN "換料設置" +#define FILAMENT_IN_LENGTH_T_CN "進料長度" +#define FILAMENT_IN_SPEED_T_CN "進料速度" +#define FILAMENT_TEMPERATURE_T_CN "換料溫度" +#define FILAMENT_OUT_LENGTH_T_CN "退料長度" +#define FILAMENT_OUT_SPEED_T_CN "退料速度" + +#define LEVELING_CONF_TITLE_T_CN "機器參數>調平設置" +#define LEVELING_PARA_CONF_T_CN "調平設置" +#define LEVELING_MANUAL_POS_T_CN "手動調平坐標設置" +#define LEVELING_AUTO_COMMAND_T_CN "自動調平指令設置" +#define LEVELING_AUTO_ZOFFSET_T_CN "擠出頭與調平開關偏移設置" +#define LEVELING_TOUCHMI_T_CN "機器參數>TouchMi-Probe" +#define TM_INIT_T_CN "初始化" +#define TM_ZOFFSETPOS_T_CN "Zoffset+" +#define TM_ZOFFSETNEG_T_CN "Zoffset-" +#define TM_SAVE_T_CN "保存" +#define TM_TEST_T_CN "測試" + +#define BLTOUCH_LEVELING_TITTLE_T_CN "機器參數>BL-Touch Probe" +#define BLTOUCH_LEVELING_T_CN "BL-Touch Probe" +#define BLTOUCH_INIT_T_CN "初始化" +#define BLTOUCH_ZOFFSETPOS_T_CN "Zoffset+" +#define BLTOUCH_ZOFFSETNEG_T_CN "Zoffset-" +#define BLTOUCH_SAVE_T_CN "保存" +#define BLTOUCH_TEST_T_CN "測試" + +#define LEVELING_PARA_CONF_TITLE_T_CN "調平參數" +#define AUTO_LEVELING_ENABLE_T_CN "自動調平" +#define BLTOUCH_LEVELING_ENABLE_T_CN "啟動BLtouch" +#define PROBE_PORT_T_CN "調平探針接口" +#define PROBE_X_OFFSET_T_CN "探針X方向偏移" +#define PROBE_Y_OFFSET_T_CN "探针Y方向偏移" +#define PROBE_Z_OFFSET_T_CN "探针Z方向偏移" +#define PROBE_XY_SPEED_T_CN "探针XY方向移動速度" +#define PROBE_Z_SPEED_T_CN "探针Z方向移動速度" +#define ENABLE_T_CN "是" +#define DISABLE_T_CN "否" +#define LOCKED_T_CN "否" +#define Z_MIN_T_CN "ZMin" +#define Z_MAX_T_CN "ZMax" + +#define DELTA_LEVEL_CONF_TITLE_T_CN "Delta機器參數" +#define DELTA_LEVEL_CONF_T_CN "Delta機器調平" +#define DELTA_MACHINE_RADIUS_T_CN "機器半徑" +#define DELTA_DIAGONAL_ROD_T_CN "機器桿長" +#define DELTA_PRINT_RADIUS_T_CN "打印半徑" +#define DELTA_HEIGHT_T_CN "打印高度" +#define SMOOTH_ROD_OFFSET_T_CN "滑塊偏移" +#define EFFECTOR_OFFSET_T_CN "效應器偏移" +#define CALIBRATION_RADIUS_T_CN "調平半徑" + +#define XYZ_LEVEL_CONF_TITLE_T_CN "XYZ機器參數" +#define PROBE_REACH_MAX_LEFT_T_CN "探针達到最左位置" +#define PROBE_REACH_MAX_RIGHT_T_CN "探针達到最右位置" +#define PROBE_REACH_MAX_FRONT_T_CN "探针達到最前位置" +#define PROBE_REACH_MAX_BACK_T_CN "探针達到最後位置" + +#define TEMPERATURE_CONF_TITLE_T_CN "機器參數>溫度設置" +#define NOZZLE_CONF_T_CN "噴頭設置" +#define HOTBED_CONF_T_CN "熱床設置" +#define PREHEAT_TEMPER_T_CN "預設溫度" + +#define NOZZLE_CONF_TITLE_T_CN "機器參數>噴頭設置" +#define NOZZLECNT_T_CN "噴頭數量" +#define NOZZLE_TYPE_T_CN "E0溫感類型" +#define NOZZLE_ADJUST_TYPE_T_CN "PID調溫" +#define NOZZLE_MIN_TEMPERATURE_T_CN "最低溫度" +#define NOZZLE_MAX_TEMPERATURE_T_CN "最高溫度" +#define EXTRUD_MIN_TEMPER_T_CN "最低擠出溫度" + +#define HOTBED_CONF_TITLE_T_CN "機器參數>熱床設置" +#define HOTBED_ADJUST_T_CN "PID調溫" +#define HOTBED_MIN_TEMPERATURE_T_CN "最低溫度" +#define HOTBED_MAX_TEMPERATURE_T_CN "最高溫度" + +#define MOTOR_CONF_TITLE_T_CN "機器參數>電機設置" +#define MAXFEEDRATE_CONF_T_CN "最大速度設置" +#define ACCELERATION_CONF_T_CN "加速度設置" +#define JERKCONF_T_CN "突變速度設置" +#define STEPSCONF_T_CN "脈沖設置" +#define TMC_CURRENT_T_CN "TMC 驅動電流設置" +#define TMC_STEP_MODE_T_CN "TMC 驅動模式設置" +#define MOTORDIRCONF_T_CN "電機方向設置" +#define HOMEFEEDRATECONF_T_CN "歸零速度設置" +#define HOMING_SENSITIVITY_CONF_T_CN "無限位回零靈敏度調節" + +#define MAXFEEDRATE_CONF_TITLE_T_CN "機器參數>最大速度" +#define X_MAXFEEDRATE_T_CN "X軸最大速度" +#define Y_MAXFEEDRATE_T_CN "Y軸最大速度" +#define Z_MAXFEEDRATE_T_CN "Z軸最大速度" +#define E0_MAXFEEDRATE_T_CN "E0軸最大速度" +#define E1_MAXFEEDRATE_T_CN "E1軸最大速度" + +#define ACCELERATION_CONF_TITLE_T_CN "機器參數>加速度" +#define PRINT_ACCELERATION_T_CN "打印加速度" +#define RETRACT_ACCELERATION_T_CN "回抽加速度" +#define TRAVEL_ACCELERATION_T_CN "空載加速度" +#define X_ACCELERATION_T_CN "X軸加速度" +#define Y_ACCELERATION_T_CN "Y軸加速度" +#define Z_ACCELERATION_T_CN "Z軸加速度" +#define E0_ACCELERATION_T_CN "E0軸加速度" +#define E1_ACCELERATION_T_CN "E1軸加速度" + +#define JERK_CONF_TITLE_T_CN "機器參數>突變速度" +#define X_JERK_T_CN "X軸突變速度" +#define Y_JERK_T_CN "Y軸突變速度" +#define Z_JERK_T_CN "Z軸突變速度" +#define E_JERK_T_CN "E軸突變速度" + +#define STEPS_CONF_TITLE_T_CN "機器參數>脈衝設置" +#define X_STEPS_T_CN "X軸脈沖" +#define Y_STEPS_T_CN "Y軸脈沖" +#define Z_STEPS_T_CN "Z軸脈沖" +#define E0_STEPS_T_CN "E0軸脈沖" +#define E1_STEPS_T_CN "E1軸脈沖" + +#define TMC_CURRENT_CONF_TITLE_T_CN "機器參數>TMC電流設置" +#define X_TMC_CURRENT_T_CN "X軸電流(毫安)" +#define Y_TMC_CURRENT_T_CN "Y軸電流(毫安)" +#define Z_TMC_CURRENT_T_CN "Z軸電流(毫安)" +#define E0_TMC_CURRENT_T_CN "E0軸電流(毫安)" +#define E1_TMC_CURRENT_T_CN "E1軸電流(毫安)" + +#define TMC_MODE_CONF_TITLE_T_CN "機器參數>TMC模式設置" +#define X_TMC_MODE_T_CN "X軸是否使能靜音模式" +#define Y_TMC_MODE_T_CN "Y軸是否使能靜音模式" +#define Z_TMC_MODE_T_CN "Z軸是否使能靜音模式" +#define E0_TMC_MODE_T_CN "E0軸是否使能靜音模式" +#define E1_TMC_MODE_T_CN "E1軸是否使能靜音模式" + +#define MOTORDIR_CONF_TITLE_T_CN "機器參數>電機方向" +#define X_MOTORDIR_T_CN "X軸電機方向" +#define Y_MOTORDIR_T_CN "Y軸電機方向" +#define Z_MOTORDIR_T_CN "Z軸電機方向" +#define E0_MOTORDIR_T_CN "E0軸電機方向" +#define E1_MOTORDIR_T_CN "E1軸電機方向" +#define INVERT_P_T_CN "正向" +#define INVERT_N_T_CN "反向" + +#define HOMEFEEDRATE_CONF_TITLE_T_CN "機器參數>歸零速度" +#define X_HOMESPEED_T_CN "XY軸歸零速度" +#define Y_HOMESPEED_T_CN "Y軸歸零速度" +#define Z_HOMESPEED_T_CN "Z軸歸零速度" + +#define ADVANCED_CONF_TITLE_T_CN "機器參數>高級設置" +#define PWROFF_DECTION_T_CN "斷電檢測模塊" +#define PWROFF_AFTER_PRINT_T_CN "啟動打完關機功能" +#define HAVE_UPS_T_CN "機器配備UPS電壓" +#define Z2_AND_Z2ENDSTOP_CONF_T_CN "雙z軸雙限位功能設置" +#define ENABLE_PINS_CONF_T_CN "電機使能腳電平設置" +#define WIFI_SETTINGS_T_CN "Wi-Fi參數設置" +#define ENCODER_SETTINGS_T_CN "旋鈕設置" + +#define Z2_AND_Z2ENDSTOP_CONF_TITLE_T_CN "雙z軸雙限位設置" +#define Z2_ENABLE_T_CN "啟用Z2軸" +#define Z2_ENDSTOP_T_CN "啟用Z2限位" +#define Z2_PORT_T_CN "Z2限位接口" + +#define ENABLE_PINS_CONF_TITLE_T_CN "電機使能腳電平" +#define X_ENABLE_PINS_INVERT_T_CN "X軸電機使能電平" +#define Y_ENABLE_PINS_INVERT_T_CN "Y軸電機使能電平" +#define Z_ENABLE_PINS_INVERT_T_CN "Z軸電機使能電平" +#define E_ENABLE_PINS_INVERT_T_CN "E軸電機使能電平" + +#define PAUSE_POSITION_T_CN "打印暫停位置設置" +#define PAUSE_POSITION_X_T_CN "X軸暫停位置(絕對位置,-1無效)" +#define PAUSE_POSITION_Y_T_CN "Y軸暫停位置(絕對位置,-1無效)" +#define PAUSE_POSITION_Z_T_CN "Z軸暫停位置(相對位置,-1無效)" +#define WIFI_SETTINGS_TITLE_T_CN "機器參數>Wi-Fi設置" +#define WIFI_SETTINGS_MODE_T_CN "Wi-Fi 模式" +#define WIFI_SETTINGS_NAME_T_CN "Wi-Fi 名稱: " +#define WIFI_SETTINGS_PASSWORD_T_CN "Wi-Fi 密碼: " +#define WIFI_SETTINGS_CLOUD_T_CN "是否使用雲服務?" +#define WIFI_SETTINGS_CONFIG_T_CN "配置" +#define WIFI_SETTINGS_EDIT_T_CN "編輯" +#define WIFI_CONFIG_TIPS_T_CN "進行Wi-Fi配置?" + +#define OFFSET_TITLE_T_CN "機器參數>偏移設置" +#define OFFSET_X_T_CN "X軸與調平開關偏移" +#define OFFSET_Y_T_CN "Y軸與調平開關偏移" +#define OFFSET_Z_T_CN "Z軸與調平開關偏移" + +#define HOMING_SENSITIVITY_CONF_TITLE_T_CN "機器參數>靈敏度調節" +#define X_SENSITIVITY_T_CN "X軸靈敏度" +#define Y_SENSITIVITY_T_CN "Y軸靈敏度" +#define Z_SENSITIVITY_T_CN "Z軸靈敏度" +#define Z2_SENSITIVITY_T_CN "Z2軸靈敏度" + +#define ENCODER_CONF_TITLE_T_CN "機器參數>旋鈕設置" +#define ENCODER_CONF_TEXT_T_CN "是否使用旋鈕功能?" + +#define TOOL_TEXT_T_CN "工具" +#define PREHEAT_TEXT_T_CN "預熱" +#define MOVE_TEXT_T_CN "移動" +#define HOME_TEXT_T_CN "回零" +#define PRINT_TEXT_T_CN "打印" +#define EXTRUDE_TEXT_T_CN "擠出" +#define LEVELING_TEXT_T_CN "調平" +#define AUTO_LEVELING_TEXT_T_CN "自動調平" +#define SET_TEXT_T_CN "設置" +#define MORE_TEXT_T_CN "更多" + +#define ADD_TEXT_T_CN "增加" +#define DEC_TEXT_T_CN "減少" +#define EXTRUDER_1_TEXT_T_CN "噴頭1" +#define EXTRUDER_2_TEXT_T_CN "噴頭2" +#define HEATBED_TEXT_T_CN "熱床" +#define TEXT_1C_T_CN "1℃" +#define TEXT_5C_T_CN "5℃" +#define TEXT_10C_T_CN "10℃" +#define CLOSE_TEXT_T_CN "關閉" + +#define BACK_TEXT_T_CN "返回" + +#define TOOL_PREHEAT_T_CN "預熱" +#define TOOL_EXTRUDE_T_CN "擠出" +#define TOOL_MOVE_T_CN "移動" +#define TOOL_HOME_T_CN "回零" +#define TOOL_LEVELING_T_CN "調平" +#define TOOL_AUTO_LEVELING_T_CN "自動調平" +#define TOOL_FILAMENT_T_CN "換料" +#define TOOL_MORE_T_CN "更多" + +#define AXIS_X_ADD_TEXT_T_CN "X+" +#define AXIS_X_DEC_TEXT_T_CN "X-" +#define AXIS_Y_ADD_TEXT_T_CN "Y+" +#define AXIS_Y_DEC_TEXT_T_CN "Y-" +#define AXIS_Z_ADD_TEXT_T_CN "Z+" +#define AXIS_Z_DEC_TEXT_T_CN "Z-" +#define TEXT_01MM_T_CN "0.1mm" +#define TEXT_1MM_T_CN "1mm" +#define TEXT_10MM_T_CN "10mm" + +#define HOME_X_TEXT_T_CN "X" +#define HOME_Y_TEXT_T_CN "Y" +#define HOME_Z_TEXT_T_CN "Z" +#define HOME_ALL_TEXT_T_CN "回零" +#define HOME_STOPMOVE_T_CN "急停" + +#define PAGE_UP_TEXT_T_CN "上一頁" +#define PAGE_DOWN_TEXT_T_CN "下一頁" + +#define EXTRUDER_IN_TEXT_T_CN "進料" +#define EXTRUDER_OUT_TEXT_T_CN "退料" +#define EXTRUDE_1MM_TEXT_T_CN "1mm" +#define EXTRUDE_5MM_TEXT_T_CN "5mm" +#define EXTRUDE_10MM_TEXT_T_CN "10mm" +#define EXTRUDE_LOW_SPEED_TEXT_T_CN "低速" +#define EXTRUDE_MEDIUM_SPEED_TEXT_T_CN "常速" +#define EXTRUDE_HIGH_SPEED_TEXT_T_CN "高速" + +#define LEVELING_POINT1_TEXT_T_CN "第一點" +#define LEVELING_POINT2_TEXT_T_CN "第二點" +#define LEVELING_POINT3_TEXT_T_CN "第三點" +#define LEVELING_POINT4_TEXT_T_CN "第四點" +#define LEVELING_POINT5_TEXT_T_CN "第五點" + +#define FILESYS_TEXT_T_CN "文件系統" +#define WIFI_TEXT_T_CN "WIFI" +#define FAN_TEXT_T_CN "風扇" +#define ABOUT_TEXT_T_CN "關於" +#define BREAK_POINT_TEXT_T_CN "斷點續打" +#define FILAMENT_TEXT_T_CN "換料" +#define LANGUAGE_TEXT_T_CN "語言" +#define MOTOR_OFF_TEXT_T_CN "關閉電機" +#define MOTOR_OFF_XY_TEXT_T_CN "關閉XY" +#define SHUTDOWN_TEXT_T_CN "關機" +#define MACHINE_PARA_T_CN "機器參數" +#define EEPROM_SETTINGS_T_CN "Eeprom設置" + +#define U_DISK_TEXT_T_CN "U盤" +#define SD_CARD_TEXT_T_CN "SD卡" +#define WIFI_NAME_TEXT_T_CN "無線網絡:" +#define WIFI_KEY_TEXT_T_CN "密碼: " +#define WIFI_IP_TEXT_T_CN "IP: " +#define WIFI_AP_TEXT_T_CN "狀態: AP" +#define WIFI_STA_TEXT_T_CN "狀態: STA" +#define WIFI_CONNECTED_TEXT_T_CN "已連接" +#define WIFI_DISCONNECTED_TEXT_T_CN "未連接" +#define WIFI_EXCEPTION_TEXT_T_CN "模塊異常" +#define CLOUD_TEXT_T_CN "雲服務" +#define CLOUD_BIND_T_CN "已綁定" +#define CLOUD_UNBIND_T_CN "解綁" +#define CLOUD_UNBINDING_T_CN "解绑中" +#define CLOUD_DISCONNECTED_T_CN "未連接" +#define CLOUD_UNBINDED_T_CN "未綁定" +#define CLOUD_BINDED_T_CN "已綁定" +#define CLOUD_DISABLE_T_CN "已禁用" + +#define FAN_ADD_TEXT_T_CN "增加" +#define FAN_DEC_TEXT_T_CN "減少" +#define FAN_OPEN_TEXT_T_CN "100%" +#define FAN_HALF_TEXT_T_CN "50%" +#define FAN_CLOSE_TEXT_T_CN "關閉" +#define FAN_TIPS1_TEXT_T_CN "風扇" +#define FAN_TIPS2_TEXT_T_CN "FAN\nClose" + +#define FILAMENT_IN_TEXT_T_CN "進料" +#define FILAMENT_OUT_TEXT_T_CN "退料" +#define FILAMENT_EXT0_TEXT_T_CN "噴頭1" +#define FILAMENT_EXT1_TEXT_T_CN "噴頭2" +#define FILAMENT_HEAT_TEXT_T_CN "預熱" +#define FILAMENT_STOP_TEXT_T_CN "停止" +#define FILAMENT_TIPS2_TEXT_T_CN "T:" +#define FILAMENT_TIPS3_TEXT_T_CN "正在進料" +#define FILAMENT_TIPS4_TEXT_T_CN "正在退料" +#define FILAMENT_TIPS5_TEXT_T_CN "溫度太低,請先預熱" +#define FILAMENT_TIPS6_TEXT_T_CN "換料完成" +#define FILAMENT_CHANGE_TEXT_T_CN "待打印機暫停后,\n請按<進料>或<退料>" + +#define FILAMENT_DIALOG_LOAD_HEAT_TIPS_T_CN "準備進料,正在加熱,請稍等" +#define FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_T_CN "準備退料,正在加熱,請稍等" +#define FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_T_CN "加熱完成,請裝載耗材后,按<確定>開始進料" +#define FILAMENT_DIALOG_LOAD_CONFIRM2_TIPS_T_CN "請裝載耗,按<確定>開始進料!" +#define FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_T_CN "加熱完成,请按<確定>開始退料!" +#define FILAMENT_DIALOG_LOADING_TIPS_T_CN "正在進料,请等待耗材加載完成!" +#define FILAMENT_DIALOG_UNLOADING_TIPS_T_CN "正在退料,请等待耗材卸載完成!" +#define FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_T_CN "進料完成,请按<確定>返回" +#define FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_T_CN "退料完成,请按<確定>返回" + +#define PRE_HEAT_EXT_TEXT_T_CN "噴頭" +#define PRE_HEAT_BED_TEXT_T_CN "熱床" + +#define FILE_LOADING_T_CN "正在載入......" +#define NO_FILE_AND_CHECK_T_CN "無文件!請插入sd卡/u盤!" +#define NO_FILE_T_CN "無文件!" + +#define EXTRUDER_TEMP_TEXT_T_CN "溫度" +#define EXTRUDER_E_LENGTH1_TEXT_T_CN "噴頭" +#define EXTRUDER_E_LENGTH2_TEXT_T_CN "噴頭" +#define EXTRUDER_E_LENGTH3_TEXT_T_CN "噴頭" + +#define ABOUT_TYPE_TEXT_T_CN "Type: " +#define ABOUT_VERSION_TEXT_T_CN "Firmware: " +#define ABOUT_WIFI_TEXT_T_CN "Wifi: " + +#define PRINTING_OPERATION_T_CN "操作" +#define PRINTING_PAUSE_T_CN "暫停" +#define PRINTING_TEMP_T_CN "溫度" +#define PRINTING_CHANGESPEED_T_CN "變速" +#define PRINTING_RESUME_T_CN "恢復" +#define PRINTING_STOP_T_CN "停止" +#define PRINTING_MORE_T_CN "更多" +#define PRINTING_EXTRUDER_T_CN "擠出" +#define PRINTING_MOVE_T_CN "移動" + +#define EXTRUDER_SPEED_T_CN "擠出" +#define MOVE_SPEED_T_CN "移動" +#define EXTRUDER_SPEED_STATE_T_CN "擠出速度" +#define MOVE_SPEED_STATE_T_CN "移動速度" +#define STEP_1PERCENT_T_CN "1%%" +#define STEP_5PERCENT_T_CN "5%%" +#define STEP_10PERCENT_T_CN "10%%" + +#define TITLE_READYPRINT_T_CN "準備打印" +#define TITLE_PREHEAT_T_CN "預熱" +#define TITLE_MOVE_T_CN "移動" +#define TITLE_HOME_T_CN "回零" +#define TITLE_EXTRUDE_T_CN "擠出" +#define TITLE_LEVELING_T_CN "調平" +#define TITLE_SET_T_CN "設置" +#define TITLE_MORE_T_CN "更多" +#define TITLE_CHOOSEFILE_T_CN "選擇文件" +#define TITLE_PRINTING_T_CN "正在打印" +#define TITLE_OPERATION_T_CN "操作" +#define TITLE_ADJUST_T_CN "調整" +#define TITLE_WIRELESS_T_CN "無線網絡" +#define TITLE_FILAMENT_T_CN "換料" +#define TITLE_ABOUT_T_CN "關於" +#define TITLE_FAN_T_CN "風扇" +#define TITLE_LANGUAGE_T_CN "語言" +#define TITLE_PAUSE_T_CN "暫停" +#define TITLE_CHANGESPEED_T_CN "變速" +#define TITLE_CLOUD_TEXT_T_CN "雲服務" +#define TITLE_DIALOG_CONFIRM_T_CN "確認" +#define TITLE_FILESYS_T_CN "文件系統" + +#define AUTO_SHUTDOWN_T_CN "自動關機" +#define MANUAL_SHUTDOWN_T_CN "手動關機" + +#define DIALOG_CONFIRM_T_CN "確定" +#define DIALOG_CANCLE_T_CN "取消" +#define DIALOG_OK_T_CN "確認" +#define DIALOG_RESET_T_CN "重設" +#define DIALOG_RETRY_T_CN "重試" +#define DIALOG_DISABLE_T_CN "禁用" +#define DIALOG_PRINT_MODEL_T_CN "打印模型?" +#define DIALOG_CANCEL_PRINT_T_CN "停止打印?" +#define DIALOG_RETRY_T_CN "重試" +#define DIALOG_STOP_T_CN "停止" +#define DIALOG_REPRINT_FROM_BREAKPOINT_T_CN "從斷點續打?" +#define DIALOG_ERROR_TIPS1_T_CN "錯誤:找不到文件,請插入sd卡/u盤!" +#define DIALOG_ERROR_TIPS2_T_CN "錯誤:通信失敗,請檢查波特率或主板硬件!" +#define DIALOG_ERROR_TIPS3_T_CN "錯誤:文件名或文件路徑太長!" +#define DIALOG_CLOSE_MACHINE_T_CN "正在關機......" +#define DIALOG_UNBIND_PRINTER_T_CN "解除綁定?" +#define DIALOG_FILAMENT_NO_PRESS_T_CN "請先裝載耗材!" +#define DIALOG_PRINT_FINISH_T_CN "打印完成!" +#define DIALOG_PRINT_TIME_T_CN "打印時間: " +#define DIALOG_REPRINT_T_CN "再打印壹次" +#define DIALOG_WIFI_ENABLE_TIPS_T_CN "wifi模塊正在配置中,請稍等......" +#define DIALOG_PAUSING_TIPS_T_CN "機器暫停中..." + +#define TEXT_VALUE_T_CN "%d℃/%d℃" +#define EXTRUDE_TEXT_VALUE_T_T_CN ": %d℃" +#define WIFI_RECONNECT_TEXT_T_CN "重新連接" + +#define MESSAGE_PAUSING_T_CN "暫停中..." +#define MESSAGE_CHANGING_T_CN "等待換料開始..." +#define MESSAGE_UNLOAD_T_CN "退料中,請稍等..." +#define MESSAGE_WAITING_T_CN "點擊按鈕恢復打印" +#define MESSAGE_INSERT_T_CN "裝載耗材後,點擊按鈕開始打印" +#define MESSAGE_LOAD_T_CN "進料中,請稍等..." +#define MESSAGE_PURGE_T_CN "等待擠出..." +#define MESSAGE_RESUME_T_CN "等待恢復打印..." +#define MESSAGE_HEAT_T_CN "按下按鈕,加熱噴頭" +#define MESSAGE_HEATING_T_CN "噴頭加熱中,請等待..." +#define MESSAGE_OPTION_T_CN "擠出更多還是繼續打印" +#define MESSAGE_PURGE_MORE_T_CN "擠出" +#define MESSAGE_CONTINUE_PRINT_T_CN "打印" + +#define EEPROM_SETTINGS_TITLE_T_CN "EEPROM 設置" +#define EEPROM_SETTINGS_STORE_T_CN "保存參數至EEPROM" +#define EEPROM_SETTINGS_READ_T_CN "讀取EEPROM參數" +#define EEPROM_SETTINGS_REVERT_T_CN "恢復默認參數" + +#define EEPROM_STORE_TIPS_T_CN "是否保存參數到EEPROM?" +#define EEPROM_READ_TIPS_T_CN "是否使用EEPROM參數?" +#define EEPROM_REVERT_TIPS_T_CN "是否恢復默認參數?" + +#define MORE_CUSTOM1_TEXT_T_CN USER_DESC_1 +#define MORE_CUSTOM2_TEXT_T_CN USER_DESC_2 +#define MORE_CUSTOM3_TEXT_T_CN USER_DESC_3 +#define MORE_CUSTOM4_TEXT_T_CN USER_DESC_4 +#define MORE_CUSTOM5_TEXT_T_CN USER_DESC_5 +#define MORE_CUSTOM6_TEXT_T_CN USER_DESC_6 +#define MORE_CUSTOM7_TEXT_T_CN USER_DESC_7 diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp new file mode 100644 index 0000000..d7b08fe --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.cpp @@ -0,0 +1,584 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "SPI_TFT.h" + +#include "tft_lvgl_configuration.h" +#include "draw_ready_print.h" + +#include "pic_manager.h" +#include "mks_hardware_test.h" +#include "draw_ui.h" +#include "SPIFlashStorage.h" +#include <lvgl.h> + +#include "../../../../MarlinCore.h" +#include "../../../../inc/MarlinConfig.h" + +#include HAL_PATH(../../../../HAL, tft/xpt2046.h) +#include "../../../marlinui.h" +XPT2046 touch; + +#if ENABLED(POWER_LOSS_RECOVERY) + #include "../../../../feature/powerloss.h" +#endif + +#if HAS_SERVOS + #include "../../../../module/servo.h" +#endif + +#if EITHER(PROBE_TARE, HAS_Z_SERVO_PROBE) + #include "../../../../module/probe.h" +#endif + +#if ENABLED(TOUCH_SCREEN_CALIBRATION) + #include "../../../tft_io/touch_calibration.h" + #include "draw_touch_calibration.h" +#endif + +#if ENABLED(MKS_WIFI_MODULE) + #include "wifi_module.h" +#endif + +#include <SPI.h> + +#ifndef TFT_WIDTH + #define TFT_WIDTH 480 +#endif +#ifndef TFT_HEIGHT + #define TFT_HEIGHT 320 +#endif + +#if HAS_SPI_FLASH_FONT + extern void init_gb2312_font(); +#endif + +static lv_disp_buf_t disp_buf; +lv_group_t* g; +#if ENABLED(SDSUPPORT) + extern void UpdateAssets(); +#endif +uint16_t DeviceCode = 0x9488; +extern uint8_t sel_id; + +uint8_t bmp_public_buf[14 * 1024]; +uint8_t public_buf[513]; + +extern bool flash_preview_begin, default_preview_flg, gcode_preview_over; + +void SysTick_Callback() { + lv_tick_inc(1); + print_time_count(); + #if ENABLED(MKS_WIFI_MODULE) + if (tips_disp.timer == TIPS_TIMER_START) + tips_disp.timer_count++; + #endif + if (uiCfg.filament_loading_time_flg == 1) { + uiCfg.filament_loading_time_cnt++; + uiCfg.filament_rate = (uint32_t)(((uiCfg.filament_loading_time_cnt / (uiCfg.filament_loading_time * 1000.0)) * 100.0) + 0.5); + if (uiCfg.filament_loading_time_cnt >= (uiCfg.filament_loading_time * 1000)) { + uiCfg.filament_loading_time_cnt = 0; + uiCfg.filament_loading_time_flg = 0; + uiCfg.filament_loading_completed = 1; + } + } + if (uiCfg.filament_unloading_time_flg == 1) { + uiCfg.filament_unloading_time_cnt++; + uiCfg.filament_rate = (uint32_t)(((uiCfg.filament_unloading_time_cnt / (uiCfg.filament_unloading_time * 1000.0)) * 100.0) + 0.5); + if (uiCfg.filament_unloading_time_cnt >= (uiCfg.filament_unloading_time * 1000)) { + uiCfg.filament_unloading_time_cnt = 0; + uiCfg.filament_unloading_time_flg = 0; + uiCfg.filament_unloading_completed = 1; + uiCfg.filament_rate = 100; + } + } +} + +void tft_lvgl_init() { + + W25QXX.init(SPI_QUARTER_SPEED); + + gCfgItems_init(); + ui_cfg_init(); + disp_language_init(); + + watchdog_refresh(); // LVGL init takes time + + #if MB(MKS_ROBIN_NANO) + OUT_WRITE(PB0, LOW); // HE1 + #endif + + // Init TFT first! + SPI_TFT.spi_init(SPI_FULL_SPEED); + SPI_TFT.LCD_init(); + + #if ENABLED(USB_FLASH_DRIVE_SUPPORT) + uint16_t usb_flash_loop = 1000; + do { + Sd2Card::idle(); + watchdog_refresh(); + delay(2); + } while((!Sd2Card::isInserted()) && (usb_flash_loop--)); + card.mount(); + #elif HAS_LOGO_IN_FLASH + delay(2000); + #endif + + watchdog_refresh(); // LVGL init takes time + + #if ENABLED(SDSUPPORT) + UpdateAssets(); + watchdog_refresh(); // LVGL init takes time + #endif + + mks_test_get(); + + touch.Init(); + + lv_init(); + + lv_disp_buf_init(&disp_buf, bmp_public_buf, nullptr, LV_HOR_RES_MAX * 14); /*Initialize the display buffer*/ + + lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ + lv_disp_drv_init(&disp_drv); /*Basic initialization*/ + disp_drv.flush_cb = my_disp_flush; /*Set your driver function*/ + disp_drv.buffer = &disp_buf; /*Assign the buffer to the display*/ + lv_disp_drv_register(&disp_drv); /*Finally register the driver*/ + + lv_indev_drv_t indev_drv; + lv_indev_drv_init(&indev_drv); /*Descriptor of a input device driver*/ + indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/ + indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/ + lv_indev_drv_register(&indev_drv); /*Finally register the driver*/ + + #if HAS_ROTARY_ENCODER + g = lv_group_create(); + lv_indev_drv_t enc_drv; + lv_indev_drv_init(&enc_drv); + enc_drv.type = LV_INDEV_TYPE_ENCODER; + enc_drv.read_cb = my_mousewheel_read; + lv_indev_t * enc_indev = lv_indev_drv_register(&enc_drv); + lv_indev_set_group(enc_indev, g); + #endif + + lv_fs_drv_t spi_flash_drv; + lv_fs_drv_init(&spi_flash_drv); + spi_flash_drv.letter = 'F'; + spi_flash_drv.open_cb = spi_flash_open_cb; + spi_flash_drv.close_cb = spi_flash_close_cb; + spi_flash_drv.read_cb = spi_flash_read_cb; + spi_flash_drv.seek_cb = spi_flash_seek_cb; + spi_flash_drv.tell_cb = spi_flash_tell_cb; + lv_fs_drv_register(&spi_flash_drv); + + lv_fs_drv_t sd_drv; + lv_fs_drv_init(&sd_drv); + sd_drv.letter = 'S'; + sd_drv.open_cb = sd_open_cb; + sd_drv.close_cb = sd_close_cb; + sd_drv.read_cb = sd_read_cb; + sd_drv.seek_cb = sd_seek_cb; + sd_drv.tell_cb = sd_tell_cb; + lv_fs_drv_register(&sd_drv); + + systick_attach_callback(SysTick_Callback); + + #if HAS_SPI_FLASH_FONT + init_gb2312_font(); + #endif + + tft_style_init(); + + filament_pin_setup(); + + lv_encoder_pin_init(); + + #if ENABLED(MKS_WIFI_MODULE) + mks_esp_wifi_init(); + //WIFISERIAL.begin(WIFI_BAUDRATE); + //uint32_t serial_connect_timeout = millis() + 1000UL; + //while (/*!WIFISERIAL && */PENDING(millis(), serial_connect_timeout)) { /*nada*/ } + mks_wifi_firmware_upddate(); + #endif + TERN_(HAS_SERVOS, servo_init()); + TERN_(HAS_Z_SERVO_PROBE, probe.servo_probe_init()); + bool ready = true; + #if ENABLED(POWER_LOSS_RECOVERY) + recovery.load(); + if (recovery.valid()) { + ready = false; + if (gCfgItems.from_flash_pic) + flash_preview_begin = true; + else + default_preview_flg = true; + + uiCfg.print_state = REPRINTING; + + #if ENABLED(LONG_FILENAME_HOST_SUPPORT) + strncpy(public_buf_m, recovery.info.sd_filename, sizeof(public_buf_m)); + card.printLongPath(public_buf_m); + strncpy(list_file.long_name[sel_id], card.longFilename, sizeof(list_file.long_name[sel_id])); + #else + strncpy(list_file.long_name[sel_id], recovery.info.sd_filename, sizeof(list_file.long_name[sel_id])); + #endif + lv_draw_printing(); + } + #endif + + if (ready) { + lv_draw_ready_print(); + } + + if (mks_test_flag == 0x1E) + mks_gpio_test(); +} + +void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p) { + uint16_t width = area->x2 - area->x1 + 1, + height = area->y2 - area->y1 + 1; + + SPI_TFT.setWindow((uint16_t)area->x1, (uint16_t)area->y1, width, height); + + for (uint16_t i = 0; i < height; i++) + SPI_TFT.tftio.WriteSequence((uint16_t*)(color_p + width * i), width); + + lv_disp_flush_ready(disp); /* Indicate you are ready with the flushing*/ + + W25QXX.init(SPI_QUARTER_SPEED); +} + +void lv_fill_rect(lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2, lv_color_t bk_color) { + uint16_t width, height; + width = x2 - x1 + 1; + height = y2 - y1 + 1; + + SPI_TFT.setWindow((uint16_t)x1, (uint16_t)y1, width, height); + #if ENABLED(TFT_LVGL_UI_FSMC) + SPI_TFT.tftio.WriteReg(0x002C); + #endif + + #ifdef LCD_USE_DMA_FSMC + SPI_TFT.tftio.WriteMultiple(bk_color.full, width * height); + #else + for (uint32_t i = 0; i < width * height; i++) + SPI_TFT.tftio.WriteData(bk_color.full); + #endif + + #if ENABLED(TFT_LVGL_UI_SPI) + W25QXX.init(SPI_QUARTER_SPEED); + #endif +} + +#define TICK_CYCLE 1 + +unsigned int getTickDiff(unsigned int curTick, unsigned int lastTick) { + return TICK_CYCLE * (lastTick <= curTick ? (curTick - lastTick) : (0xFFFFFFFF - lastTick + curTick)); +} + +static bool get_point(int16_t *x, int16_t *y) { + bool is_touched = touch.getRawPoint(x, y); + + if (!is_touched) return false; + + #if ENABLED(TOUCH_SCREEN_CALIBRATION) + const calibrationState state = touch_calibration.get_calibration_state(); + if (state >= CALIBRATION_TOP_LEFT && state <= CALIBRATION_BOTTOM_RIGHT) { + if (touch_calibration.handleTouch(*x, *y)) lv_update_touch_calibration_screen(); + return false; + } + *x = int16_t((int32_t(*x) * touch_calibration.calibration.x) >> 16) + touch_calibration.calibration.offset_x; + *y = int16_t((int32_t(*y) * touch_calibration.calibration.y) >> 16) + touch_calibration.calibration.offset_y; + #else + *x = int16_t((int32_t(*x) * TOUCH_CALIBRATION_X) >> 16) + TOUCH_OFFSET_X; + *y = int16_t((int32_t(*y) * TOUCH_CALIBRATION_Y) >> 16) + TOUCH_OFFSET_Y; + #endif + + return true; +} + +bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data) { + static int16_t last_x = 0, last_y = 0; + static uint8_t last_touch_state = LV_INDEV_STATE_REL; + static int32_t touch_time1 = 0; + uint32_t tmpTime, diffTime = 0; + + tmpTime = millis(); + diffTime = getTickDiff(tmpTime, touch_time1); + if (diffTime > 20) { + if (get_point(&last_x, &last_y)) { + + if (last_touch_state == LV_INDEV_STATE_PR) return false; + data->state = LV_INDEV_STATE_PR; + + // Set the coordinates (if released use the last-pressed coordinates) + #if TFT_ROTATION == TFT_ROTATE_180 + data->point.x = TFT_WIDTH - last_x; + data->point.y = TFT_HEIGHT -last_y; + #else + data->point.x = last_x; + data->point.y = last_y; + #endif + + last_x = last_y = 0; + last_touch_state = LV_INDEV_STATE_PR; + } + else { + if (last_touch_state == LV_INDEV_STATE_PR) + data->state = LV_INDEV_STATE_REL; + last_touch_state = LV_INDEV_STATE_REL; + } + + touch_time1 = tmpTime; + } + + return false; // Return `false` since no data is buffering or left to read +} + +int16_t enc_diff = 0; +lv_indev_state_t state = LV_INDEV_STATE_REL; + +bool my_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) { + (void) indev_drv; /*Unused*/ + + data->state = state; + data->enc_diff = enc_diff; + enc_diff = 0; + + return false; /*No more data to read so return false*/ +} + +extern uint8_t currentFlashPage; + +//spi_flash +uint32_t pic_read_base_addr = 0, pic_read_addr_offset = 0; +lv_fs_res_t spi_flash_open_cb (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) { + static char last_path_name[30]; + if (strcasecmp(last_path_name, path) != 0) { + pic_read_base_addr = lv_get_pic_addr((uint8_t *)path); + strcpy(last_path_name, path); + } + else { + W25QXX.init(SPI_QUARTER_SPEED); + currentFlashPage = 0; + } + pic_read_addr_offset = pic_read_base_addr; + return LV_FS_RES_OK; +} + +lv_fs_res_t spi_flash_close_cb (lv_fs_drv_t * drv, void * file_p) { + lv_fs_res_t res = LV_FS_RES_OK; + /* Add your code here*/ + pic_read_addr_offset = pic_read_base_addr; + return res; +} + +lv_fs_res_t spi_flash_read_cb (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) { + lv_pic_test((uint8_t *)buf, pic_read_addr_offset, btr); + *br = btr; + return LV_FS_RES_OK; +} + +lv_fs_res_t spi_flash_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos) { + #if HAS_SPI_FLASH_COMPRESSION + if (pos == 4) { + uint8_t bmp_header[4]; + SPIFlash.beginRead(pic_read_base_addr); + SPIFlash.readData(bmp_header, 4); + currentFlashPage = 1; + } + pic_read_addr_offset = pic_read_base_addr; + #else + pic_read_addr_offset = pic_read_base_addr + pos; + #endif + return LV_FS_RES_OK; +} + +lv_fs_res_t spi_flash_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) { + *pos_p = pic_read_addr_offset - pic_read_base_addr; + return LV_FS_RES_OK; +} + +//sd +char *cur_namefff; +uint32_t sd_read_base_addr = 0, sd_read_addr_offset = 0, small_image_size = 409; +char last_path[(SHORT_NAME_LEN + 1) * MAX_DIR_LEVEL + strlen("S:/") + 1]; +lv_fs_res_t sd_open_cb (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode) { + if (path != nullptr && card.isFileOpen() && strcmp((const char*)path, (const char*)last_path) == 0) return LV_FS_RES_OK; + strcpy(last_path, path); + lv_close_gcode_file(); + char name_buf[100]; + *name_buf = '/'; + strcpy(name_buf + 1, path); + char *temp = strstr(name_buf, ".bin"); + if (temp) strcpy(temp, ".GCO"); + sd_read_base_addr = lv_open_gcode_file((char *)name_buf); + sd_read_addr_offset = sd_read_base_addr; + if (sd_read_addr_offset == UINT32_MAX) return LV_FS_RES_NOT_EX; + // find small image size + card.read(public_buf, 512); + public_buf[511] = '\0'; + char* eol = strpbrk((const char*)public_buf, "\n\r"); + small_image_size = (uintptr_t)eol - (uintptr_t)((uint32_t *)(&public_buf[0])) + 1; + return LV_FS_RES_OK; +} + +lv_fs_res_t sd_close_cb (lv_fs_drv_t * drv, void * file_p) { + /* Add your code here*/ + //lv_close_gcode_file(); + return LV_FS_RES_OK; +} + +lv_fs_res_t sd_read_cb (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br) { + if (btr == 200) { + lv_gcode_file_read((uint8_t *)buf); + //pic_read_addr_offset += 208; + *br = 200; + } + else if (btr == 4) { + uint8_t header_pic[4] = { 0x04, 0x90, 0x81, 0x0C }; + memcpy(buf, header_pic, 4); + *br = 4; + } + return LV_FS_RES_OK; +} + +lv_fs_res_t sd_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos) { + sd_read_addr_offset = sd_read_base_addr + (pos - 4) / 200 * small_image_size; + lv_gcode_file_seek(sd_read_addr_offset); + return LV_FS_RES_OK; +} + +lv_fs_res_t sd_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) { + if (sd_read_addr_offset) *pos_p = 0; + else *pos_p = (sd_read_addr_offset - sd_read_base_addr) / small_image_size * 200 + 4; + return LV_FS_RES_OK; +} + +void lv_encoder_pin_init() { + #if BUTTON_EXISTS(EN1) + SET_INPUT_PULLUP(BTN_EN1); + #endif + #if BUTTON_EXISTS(EN2) + SET_INPUT_PULLUP(BTN_EN2); + #endif + #if BUTTON_EXISTS(ENC) + SET_INPUT_PULLUP(BTN_ENC); + #endif + + #if BUTTON_EXISTS(BACK) + SET_INPUT_PULLUP(BTN_BACK); + #endif + + #if BUTTON_EXISTS(UP) + SET_INPUT(BTN_UP); + #endif + #if BUTTON_EXISTS(DWN) + SET_INPUT(BTN_DWN); + #endif + #if BUTTON_EXISTS(LFT) + SET_INPUT(BTN_LFT); + #endif + #if BUTTON_EXISTS(RT) + SET_INPUT(BTN_RT); + #endif +} + +#if 1 // HAS_ENCODER_ACTION + void lv_update_encoder() { + static uint32_t encoder_time1; + uint32_t tmpTime, diffTime = 0; + tmpTime = millis(); + diffTime = getTickDiff(tmpTime, encoder_time1); + if (diffTime > 50) { + + #if HAS_ENCODER_WHEEL + + #if ANY_BUTTON(EN1, EN2, ENC, BACK) + + uint8_t newbutton = 0; + + #if BUTTON_EXISTS(EN1) + if (BUTTON_PRESSED(EN1)) newbutton |= EN_A; + #endif + #if BUTTON_EXISTS(EN2) + if (BUTTON_PRESSED(EN2)) newbutton |= EN_B; + #endif + #if BUTTON_EXISTS(ENC) + if (BUTTON_PRESSED(ENC)) newbutton |= EN_C; + #endif + #if BUTTON_EXISTS(BACK) + if (BUTTON_PRESSED(BACK)) newbutton |= EN_D; + #endif + + #else + + constexpr uint8_t newbutton = 0; + + #endif + + + static uint8_t buttons = 0; + buttons = newbutton; + static uint8_t lastEncoderBits; + + #define encrot0 0 + #define encrot1 1 + #define encrot2 2 + + uint8_t enc = 0; + if (buttons & EN_A) enc |= B01; + if (buttons & EN_B) enc |= B10; + if (enc != lastEncoderBits) { + switch (enc) { + case encrot1: + if (lastEncoderBits == encrot0) { + enc_diff--; + encoder_time1 = tmpTime; + } + break; + case encrot2: + if (lastEncoderBits == encrot0) { + enc_diff++; + encoder_time1 = tmpTime; + } + break; + } + lastEncoderBits = enc; + } + static uint8_t last_button_state = LV_INDEV_STATE_REL; + const uint8_t enc_c = (buttons & EN_C) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + if (enc_c != last_button_state) { + state = enc_c ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; + last_button_state = enc_c; + } + + #endif // HAS_ENCODER_WHEEL + + } // next_button_update_ms + } + +#endif // HAS_ENCODER_ACTION + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.h new file mode 100644 index 0000000..018f737 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_lvgl_configuration.h @@ -0,0 +1,69 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +/** + * @file lcd/extui/lib/mks_ui/tft_lvgl_configuration.h + * @date 2020-02-21 + */ + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +#include <lvgl.h> + +//#define TFT_ROTATION TFT_ROTATE_180 + +extern uint8_t bmp_public_buf[14 * 1024]; +extern uint8_t public_buf[513]; + +extern void tft_lvgl_init(); +extern void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p); +extern bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data); +extern bool my_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); + +extern void LCD_Clear(uint16_t Color); +extern void tft_set_point(uint16_t x, uint16_t y, uint16_t point); +extern void LCD_setWindowArea(uint16_t StartX, uint16_t StartY, uint16_t width, uint16_t heigh); +extern void LCD_WriteRAM_Prepare(void); +extern void lcd_draw_logo(); +extern void lv_encoder_pin_init(); +extern void lv_update_encoder(); + +extern lv_fs_res_t spi_flash_open_cb (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode); +extern lv_fs_res_t spi_flash_close_cb (lv_fs_drv_t * drv, void * file_p); +extern lv_fs_res_t spi_flash_read_cb (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br); +extern lv_fs_res_t spi_flash_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos); +extern lv_fs_res_t spi_flash_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p); + +extern lv_fs_res_t sd_open_cb (lv_fs_drv_t * drv, void * file_p, const char * path, lv_fs_mode_t mode); +extern lv_fs_res_t sd_close_cb (lv_fs_drv_t * drv, void * file_p); +extern lv_fs_res_t sd_read_cb (lv_fs_drv_t * drv, void * file_p, void * buf, uint32_t btr, uint32_t * br); +extern lv_fs_res_t sd_seek_cb(lv_fs_drv_t * drv, void * file_p, uint32_t pos); +extern lv_fs_res_t sd_tell_cb(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p); + +extern void lv_fill_rect(lv_coord_t x1, lv_coord_t y1, lv_coord_t x2, lv_coord_t y2, lv_color_t bk_color); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp new file mode 100644 index 0000000..f05874a --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.cpp @@ -0,0 +1,2920 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "../../../../MarlinCore.h" + +#include "draw_ui.h" +#include "tft_multi_language.h" + +// ********************************************* // + +common_menu_def common_menu; +main_menu_def main_menu; +preheat_menu_def preheat_menu; +move_menu_def move_menu; +home_menu_def home_menu; +file_menu_def file_menu; +extrude_menu_def extrude_menu; +leveling_menu_def leveling_menu; +set_menu_def set_menu; +more_menu_def more_menu; +wifi_menu_def wifi_menu; +cloud_menu_def cloud_menu; +about_menu_def about_menu; +fan_menu_def fan_menu; +filament_menu_def filament_menu; +printing_menu_def printing_menu; +operation_menu_def operation_menu; +pause_menu_def pause_menu; +speed_menu_def speed_menu; +printing_more_menu_def printing_more_menu; +dialog_menu_def dialog_menu; +language_menu_def language_menu; +print_file_dialog_menu_def print_file_dialog_menu; +filesys_menu_def filesys_menu; +tool_menu_def tool_menu; +MachinePara_menu_def MachinePara_menu; +pause_msg_def pause_msg_menu; +eeprom_def eeprom_menu; +touchmi_menu_def touchmi_menu; + +machine_common_def machine_menu; +void machine_setting_disp() { + if (gCfgItems.language == LANG_SIMPLE_CHINESE) { + MachinePara_menu.title = MACHINE_PARA_TITLE_CN; + MachinePara_menu.MachineSetting = MACHINE_TYPE_CNOFIG_CN; + MachinePara_menu.MotorSetting = MOTOR_CONFIG_CN; + MachinePara_menu.leveling = MACHINE_LEVELING_CONFIG_CN; + MachinePara_menu.AdvanceSetting = ADVANCE_CONFIG_CN; + + machine_menu.default_value = DEFAULT_CN; + machine_menu.next = NEXT_CN; + machine_menu.previous = PREVIOUS_CN; + + machine_menu.MachineConfigTitle = MACHINE_CONFIG_TITLE_CN; + machine_menu.MachineType = MACHINE_TYPE_CN; + machine_menu.Stroke = MACHINE_STROKE_CN; + machine_menu.HomeDir = MACHINE_HOMEDIR_CN; + machine_menu.EndStopType = MACHINE_ENDSTOP_TYPE_CN; + machine_menu.FilamentConf = MACHINE_FILAMENT_CONFIG_CN; + + machine_menu.MachineTypeConfTitle = MACHINE_TYPE_CONFIG_TITLE_CN; + machine_menu.xyz = MACHINE_TYPE_XYZ_CN; + machine_menu.delta = MACHINE_TYPE_DELTA_CN; + machine_menu.corexy = MACHINE_TYPE_COREXY_CN; + + machine_menu.StrokeConfTitle = MACHINE_STROKE_CONF_TITLE_CN; + machine_menu.xStroke = X_MAX_LENGTH_CN; + machine_menu.yStroke = Y_MAX_LENGTH_CN; + machine_menu.zStroke = Z_MAX_LENGTH_CN; + + machine_menu.xmin = X_MIN_LENGTH_CN; + machine_menu.ymin = Y_MIN_LENGTH_CN; + machine_menu.zmin = Z_MIN_LENGTH_CN; + + machine_menu.HomeDirConfTitle = HOME_DIR_CONF_TITLE_CN; + machine_menu.xHomeDir = HOME_DIR_X_CN; + machine_menu.yHomeDir = HOME_DIR_Y_CN; + machine_menu.zHomeDir = HOME_DIR_Z_CN; + machine_menu.min = HOME_MIN_CN; + machine_menu.max = HOME_MAX_CN; + + machine_menu.EndstopConfTitle = ENDSTOP_CONF_TITLE_CN; + machine_menu.xEndstop_min = MIN_ENDSTOP_X_CN; + machine_menu.yEndstop_min = MIN_ENDSTOP_Y_CN; + machine_menu.zEndstop_min = MIN_ENDSTOP_Z_CN; + machine_menu.xEndstop_max = MAX_ENDSTOP_X_CN; + machine_menu.yEndstop_max = MAX_ENDSTOP_Y_CN; + machine_menu.zEndstop_max = MAX_ENDSTOP_Z_CN; + machine_menu.FilamentEndstop = ENDSTOP_FIL_CN; + machine_menu.LevelingEndstop = ENDSTOP_LEVEL_CN; + machine_menu.opened = ENDSTOP_OPENED_CN; + machine_menu.closed = ENDSTOP_CLOSED_CN; + + machine_menu.FilamentConfTitle = FILAMENT_CONF_TITLE_CN; + machine_menu.InLength = FILAMENT_IN_LENGTH_CN; + machine_menu.InSpeed = FILAMENT_IN_SPEED_CN; + machine_menu.FilamentTemperature = FILAMENT_TEMPERATURE_CN; + machine_menu.OutLength = FILAMENT_OUT_LENGTH_CN; + machine_menu.OutSpeed = FILAMENT_OUT_SPEED_CN; + + machine_menu.LevelingParaConfTitle = LEVELING_CONF_TITLE_CN; + machine_menu.LevelingParaConf = LEVELING_PARA_CONF_CN; + machine_menu.LevelingManuPosConf = LEVELING_MANUAL_POS_CN; + machine_menu.LevelingAutoCommandConf = LEVELING_AUTO_COMMAND_CN; + machine_menu.LevelingAutoZoffsetConf = LEVELING_AUTO_ZOFFSET_CN; + + machine_menu.LevelingSubConfTitle = LEVELING_PARA_CONF_TITLE_CN; + machine_menu.AutoLevelEnable = AUTO_LEVELING_ENABLE_CN; + machine_menu.BLtouchEnable = BLTOUCH_LEVELING_ENABLE_CN; + machine_menu.ProbePort = PROBE_PORT_CN; + machine_menu.ProbeXoffset = PROBE_X_OFFSET_CN; + machine_menu.ProbeYoffset = PROBE_Y_OFFSET_CN; + machine_menu.ProbeZoffset = PROBE_Z_OFFSET_CN; + machine_menu.ProbeXYspeed = PROBE_XY_SPEED_CN; + machine_menu.ProbeZspeed = PROBE_Z_SPEED_CN; + machine_menu.enable = ENABLE_CN; + machine_menu.disable = DISABLE_CN; + machine_menu.locked = LOCKED_CN; + machine_menu.z_min = Z_MIN_CN; + machine_menu.z_max = Z_MAX_CN; + + machine_menu.LevelingSubDeltaConfTitle = DELTA_LEVEL_CONF_TITLE_CN; + machine_menu.MachineRadius = DELTA_MACHINE_RADIUS_CN; + machine_menu.DiagonalRod = DELTA_DIAGONAL_ROD_CN; + machine_menu.PrintableRadius = DELTA_PRINT_RADIUS_CN; + machine_menu.DeltaHeight = DELTA_HEIGHT_CN; + machine_menu.SmoothRodOffset = SMOOTH_ROD_OFFSET_CN; + machine_menu.EffectorOffset = EFFECTOR_OFFSET_CN; + machine_menu.CalibrationRadius = CALIBRATION_RADIUS_CN; + + machine_menu.LevelingSubXYZConfTitle = XYZ_LEVEL_CONF_TITLE_CN; + + machine_menu.TemperatureConfTitle = TEMPERATURE_CONF_TITLE_CN; + machine_menu.NozzleConf = NOZZLE_CONF_CN; + machine_menu.HotBedConf = HOTBED_CONF_CN; + machine_menu.PreheatTemperConf = PREHEAT_TEMPER_CN; + + machine_menu.NozzleConfTitle = NOZZLE_CONF_TITLE_CN; + machine_menu.NozzleCnt = NOZZLECNT_CN; + machine_menu.NozzleType = NOZZLE_TYPE_CN; + machine_menu.NozzleAdjustType = NOZZLE_ADJUST_TYPE_CN; + machine_menu.NozzleMinTemperature = NOZZLE_MIN_TEMPERATURE_CN; + machine_menu.NozzleMaxTemperature = NOZZLE_MAX_TEMPERATURE_CN; + machine_menu.Extrude_Min_Temper = EXTRUD_MIN_TEMPER_CN; + + machine_menu.HotbedConfTitle = HOTBED_CONF_TITLE_CN; + machine_menu.HotbedAjustType = HOTBED_ADJUST_CN; + machine_menu.HotbedMinTemperature = HOTBED_MIN_TEMPERATURE_CN; + machine_menu.HotbedMaxTemperature = HOTBED_MAX_TEMPERATURE_CN; + + machine_menu.MotorConfTitle = MOTOR_CONF_TITLE_CN; + machine_menu.MaxFeedRateConf = MAXFEEDRATE_CONF_CN; + machine_menu.AccelerationConf = ACCELERATION_CONF_CN; + machine_menu.JerkConf = JERKCONF_CN; + machine_menu.StepsConf = STEPSCONF_CN; + machine_menu.TMCcurrentConf = TMC_CURRENT_CN; + machine_menu.TMCStepModeConf = TMC_STEP_MODE_CN; + machine_menu.MotorDirConf = MOTORDIRCONF_CN; + machine_menu.HomeFeedRateConf = HOMEFEEDRATECONF_CN; + machine_menu.PausePosition = PAUSE_POSITION_CN; + machine_menu.WifiSettings = WIFI_SETTINGS_CN; + machine_menu.HomingSensitivityConf = HOMING_SENSITIVITY_CONF_CN; + machine_menu.EncoderSettings = ENCODER_SETTINGS_CN; + + machine_menu.MaxFeedRateConfTitle = MAXFEEDRATE_CONF_TITLE_CN; + machine_menu.XMaxFeedRate = X_MAXFEEDRATE_CN; + machine_menu.YMaxFeedRate = Y_MAXFEEDRATE_CN; + machine_menu.ZMaxFeedRate = Z_MAXFEEDRATE_CN; + machine_menu.E0MaxFeedRate = E0_MAXFEEDRATE_CN; + machine_menu.E1MaxFeedRate = E1_MAXFEEDRATE_CN; + + machine_menu.AccelerationConfTitle = ACCELERATION_CONF_TITLE_CN; + machine_menu.PrintAcceleration = PRINT_ACCELERATION_CN; + machine_menu.RetractAcceleration = RETRACT_ACCELERATION_CN; + machine_menu.TravelAcceleration = TRAVEL_ACCELERATION_CN; + machine_menu.X_Acceleration = X_ACCELERATION_CN; + machine_menu.Y_Acceleration = Y_ACCELERATION_CN; + machine_menu.Z_Acceleration = Z_ACCELERATION_CN; + machine_menu.E0_Acceleration = E0_ACCELERATION_CN; + machine_menu.E1_Acceleration = E1_ACCELERATION_CN; + + machine_menu.JerkConfTitle = JERK_CONF_TITLE_CN; + machine_menu.X_Jerk = X_JERK_CN; + machine_menu.Y_Jerk = Y_JERK_CN; + machine_menu.Z_Jerk = Z_JERK_CN; + machine_menu.E_Jerk = E_JERK_CN; + + machine_menu.StepsConfTitle = STEPS_CONF_TITLE_CN; + machine_menu.X_Steps = X_STEPS_CN; + machine_menu.Y_Steps = Y_STEPS_CN; + machine_menu.Z_Steps = Z_STEPS_CN; + machine_menu.E0_Steps = E0_STEPS_CN; + machine_menu.E1_Steps = E1_STEPS_CN; + + machine_menu.TmcCurrentConfTitle = TMC_CURRENT_CONF_TITLE_CN; + machine_menu.X_Current = X_TMC_CURRENT_CN; + machine_menu.Y_Current = Y_TMC_CURRENT_CN; + machine_menu.Z_Current = Z_TMC_CURRENT_CN; + machine_menu.E0_Current = E0_TMC_CURRENT_CN; + machine_menu.E1_Current = E1_TMC_CURRENT_CN; + + machine_menu.TmcStepModeConfTitle = TMC_MODE_CONF_TITLE_CN; + machine_menu.X_StepMode = X_TMC_MODE_CN; + machine_menu.Y_StepMode = Y_TMC_MODE_CN; + machine_menu.Z_StepMode = Z_TMC_MODE_CN; + machine_menu.E0_StepMode = E0_TMC_MODE_CN; + machine_menu.E1_StepMode = E1_TMC_MODE_CN; + + machine_menu.MotorDirConfTitle = MOTORDIR_CONF_TITLE_CN; + machine_menu.X_MotorDir = X_MOTORDIR_CN; + machine_menu.Y_MotorDir = Y_MOTORDIR_CN; + machine_menu.Z_MotorDir = Z_MOTORDIR_CN; + machine_menu.E0_MotorDir = E0_MOTORDIR_CN; + machine_menu.E1_MotorDir = E1_MOTORDIR_CN; + machine_menu.Invert_0 = INVERT_P_CN; + machine_menu.Invert_1 = INVERT_N_CN; + + machine_menu.HomeFeedRateConfTitle = HOMEFEEDRATE_CONF_TITLE_CN; + machine_menu.XY_HomeFeedRate = X_HOMESPEED_CN; + machine_menu.Z_HomeFeedRate = Z_HOMESPEED_CN; + + machine_menu.AdvancedConfTitle = ADVANCED_CONF_TITLE_CN; + machine_menu.PwrOffDection = PWROFF_DECTION_CN; + machine_menu.PwrOffAfterPrint = PWROFF_AFTER_PRINT_CN; + machine_menu.HaveUps = HAVE_UPS_CN; + machine_menu.Z2andZ2Endstop = Z2_AND_Z2ENDSTOP_CONF_CN; + machine_menu.EnablePinsInvert = ENABLE_PINS_CONF_CN; + + machine_menu.Z2ConfTitle = Z2_AND_Z2ENDSTOP_CONF_TITLE_CN; + machine_menu.Z2Enable = Z2_ENABLE_CN; + machine_menu.Z2EndstopEnable = Z2_ENDSTOP_CN; + machine_menu.Z2Port = Z2_PORT_CN; + + machine_menu.EnablePinsInvertTitle = ENABLE_PINS_CONF_TITLE_CN; + machine_menu.XInvert = X_ENABLE_PINS_INVERT_CN; + machine_menu.YInvert = Y_ENABLE_PINS_INVERT_CN; + machine_menu.ZInvert = Z_ENABLE_PINS_INVERT_CN; + machine_menu.EInvert = E_ENABLE_PINS_INVERT_CN; + + machine_menu.key_back = KEY_BACK_CN; + machine_menu.key_reset = KEY_REST_CN; + machine_menu.key_confirm = KEY_CONFIRM_CN; + + machine_menu.PausePosText = PAUSE_POSITION_CN; + machine_menu.xPos = PAUSE_POSITION_X_CN; + machine_menu.yPos = PAUSE_POSITION_Y_CN; + machine_menu.zPos = PAUSE_POSITION_Z_CN; + machine_menu.WifiConfTitle = WIFI_SETTINGS_TITLE_CN; + machine_menu.wifiMode = WIFI_SETTINGS_MODE_CN; + machine_menu.wifiName = WIFI_SETTINGS_NAME_CN; + machine_menu.wifiPassWord = WIFI_SETTINGS_PASSWORD_CN; + machine_menu.wifiCloud = WIFI_SETTINGS_CLOUD_CN; + machine_menu.wifiConfig = WIFI_SETTINGS_CONFIG_CN; + machine_menu.wifiEdit = WIFI_SETTINGS_EDIT_CN; + machine_menu.wifiConfigTips = WIFI_CONFIG_TIPS_CN; + + machine_menu.OffsetConfTitle = OFFSET_TITLE_CN; + machine_menu.Xoffset = OFFSET_X_CN; + machine_menu.Yoffset = OFFSET_Y_CN; + machine_menu.Zoffset = OFFSET_Z_CN; + + machine_menu.LevelingTouchmiConf = LEVELING_TOUCHMI_CN; + machine_menu.TouchmiInit = TM_INIT_CN; + machine_menu.TouchmiOffsetpos = TM_ZOFFSETPOS_CN; + machine_menu.TouchmiOffsetneg = TM_ZOFFSETNEG_CN; + machine_menu.TouchmiSave = TM_SAVE_CN; + machine_menu.TouchmiTest = TM_TEST_CN; + + machine_menu.BLTouchLevelingConfTitle = BLTOUCH_LEVELING_TITTLE_CN; + machine_menu.BLTouchLevelingConf = BLTOUCH_LEVELING_CN; + machine_menu.BLTouchInit = BLTOUCH_INIT_CN; + machine_menu.BLTouchOffsetpos = BLTOUCH_ZOFFSETPOS_CN; + machine_menu.BLTouchOffsetneg = BLTOUCH_ZOFFSETNEG_CN; + machine_menu.BLTouchSave = BLTOUCH_SAVE_CN; + machine_menu.BLTouchTest = BLTOUCH_TEST_CN; + + machine_menu.HomingSensitivityConfTitle = HOMING_SENSITIVITY_CONF_TITLE_CN; + machine_menu.X_Sensitivity = X_SENSITIVITY_CN; + machine_menu.Y_Sensitivity = Y_SENSITIVITY_CN; + machine_menu.Z_Sensitivity = Z_SENSITIVITY_CN; + machine_menu.Z2_Sensitivity = Z2_SENSITIVITY_CN; + + machine_menu.EncoderConfTitle = ENCODER_CONF_TITLE_CN; + machine_menu.EncoderConfText = ENCODER_CONF_TEXT_CN; + } + else if (gCfgItems.language == LANG_COMPLEX_CHINESE) { + MachinePara_menu.title = MACHINE_PARA_TITLE_T_CN; + MachinePara_menu.MachineSetting = MACHINE_TYPE_CNOFIG_T_CN; + MachinePara_menu.MotorSetting = MOTOR_CONFIG_T_CN; + MachinePara_menu.leveling = MACHINE_LEVELING_CONFIG_T_CN; + MachinePara_menu.AdvanceSetting = ADVANCE_CONFIG_T_CN; + + machine_menu.default_value = DEFAULT_T_CN; + machine_menu.next = NEXT_T_CN; + machine_menu.previous = PREVIOUS_T_CN; + + machine_menu.MachineConfigTitle = MACHINE_CONFIG_TITLE_T_CN; + machine_menu.MachineType = MACHINE_TYPE_T_CN; + machine_menu.Stroke = MACHINE_STROKE_T_CN; + machine_menu.HomeDir = MACHINE_HOMEDIR_T_CN; + machine_menu.EndStopType = MACHINE_ENDSTOP_TYPE_T_CN; + machine_menu.FilamentConf = MACHINE_FILAMENT_CONFIG_T_CN; + + machine_menu.MachineTypeConfTitle = MACHINE_TYPE_CONFIG_TITLE_T_CN; + machine_menu.xyz = MACHINE_TYPE_XYZ_T_CN; + machine_menu.delta = MACHINE_TYPE_DELTA_T_CN; + machine_menu.corexy = MACHINE_TYPE_COREXY_T_CN; + + machine_menu.StrokeConfTitle = MACHINE_STROKE_CONF_TITLE_T_CN; + machine_menu.xStroke = X_MAX_LENGTH_T_CN; + machine_menu.yStroke = Y_MAX_LENGTH_T_CN; + machine_menu.zStroke = Z_MAX_LENGTH_T_CN; + + machine_menu.xmin = X_MIN_LENGTH_T_CN; + machine_menu.ymin = Y_MIN_LENGTH_T_CN; + machine_menu.zmin = Z_MIN_LENGTH_T_CN; + + machine_menu.HomeDirConfTitle = HOME_DIR_CONF_TITLE_T_CN; + machine_menu.xHomeDir = HOME_DIR_X_T_CN; + machine_menu.yHomeDir = HOME_DIR_Y_T_CN; + machine_menu.zHomeDir = HOME_DIR_Z_T_CN; + machine_menu.min = HOME_MIN_T_CN; + machine_menu.max = HOME_MAX_T_CN; + + machine_menu.EndstopConfTitle = ENDSTOP_CONF_TITLE_T_CN; + machine_menu.xEndstop_min = MIN_ENDSTOP_X_T_CN; + machine_menu.yEndstop_min = MIN_ENDSTOP_Y_T_CN; + machine_menu.zEndstop_min = MIN_ENDSTOP_Z_T_CN; + machine_menu.xEndstop_max = MAX_ENDSTOP_X_T_CN; + machine_menu.yEndstop_max = MAX_ENDSTOP_Y_T_CN; + machine_menu.zEndstop_max = MAX_ENDSTOP_Z_T_CN; + machine_menu.FilamentEndstop = ENDSTOP_FIL_T_CN; + machine_menu.LevelingEndstop = ENDSTOP_LEVEL_T_CN; + machine_menu.opened = ENDSTOP_OPENED_T_CN; + machine_menu.closed = ENDSTOP_CLOSED_T_CN; + + machine_menu.FilamentConfTitle = FILAMENT_CONF_TITLE_T_CN; + machine_menu.InLength = FILAMENT_IN_LENGTH_T_CN; + machine_menu.InSpeed = FILAMENT_IN_SPEED_T_CN; + machine_menu.FilamentTemperature = FILAMENT_TEMPERATURE_T_CN; + machine_menu.OutLength = FILAMENT_OUT_LENGTH_T_CN; + machine_menu.OutSpeed = FILAMENT_OUT_SPEED_T_CN; + + machine_menu.LevelingParaConfTitle = LEVELING_CONF_TITLE_T_CN; + machine_menu.LevelingParaConf = LEVELING_PARA_CONF_T_CN; + machine_menu.LevelingManuPosConf = LEVELING_MANUAL_POS_T_CN; + machine_menu.LevelingAutoCommandConf = LEVELING_AUTO_COMMAND_T_CN; + machine_menu.LevelingAutoZoffsetConf = LEVELING_AUTO_ZOFFSET_T_CN; + + machine_menu.LevelingSubConfTitle = LEVELING_PARA_CONF_TITLE_T_CN; + machine_menu.AutoLevelEnable = AUTO_LEVELING_ENABLE_T_CN; + machine_menu.BLtouchEnable = BLTOUCH_LEVELING_ENABLE_T_CN; + machine_menu.ProbePort = PROBE_PORT_T_CN; + machine_menu.ProbeXoffset = PROBE_X_OFFSET_T_CN; + machine_menu.ProbeYoffset = PROBE_Y_OFFSET_T_CN; + machine_menu.ProbeZoffset = PROBE_Z_OFFSET_T_CN; + machine_menu.ProbeXYspeed = PROBE_XY_SPEED_T_CN; + machine_menu.ProbeZspeed = PROBE_Z_SPEED_T_CN; + machine_menu.enable = ENABLE_T_CN; + machine_menu.disable = DISABLE_T_CN; + machine_menu.locked = LOCKED_T_CN; + machine_menu.z_min = Z_MIN_T_CN; + machine_menu.z_max = Z_MAX_T_CN; + + machine_menu.LevelingSubDeltaConfTitle = DELTA_LEVEL_CONF_TITLE_T_CN; + machine_menu.MachineRadius = DELTA_MACHINE_RADIUS_T_CN; + machine_menu.DiagonalRod = DELTA_DIAGONAL_ROD_T_CN; + machine_menu.PrintableRadius = DELTA_PRINT_RADIUS_T_CN; + machine_menu.DeltaHeight = DELTA_HEIGHT_T_CN; + machine_menu.SmoothRodOffset = SMOOTH_ROD_OFFSET_T_CN; + machine_menu.EffectorOffset = EFFECTOR_OFFSET_T_CN; + machine_menu.CalibrationRadius = CALIBRATION_RADIUS_T_CN; + + machine_menu.LevelingSubXYZConfTitle = XYZ_LEVEL_CONF_TITLE_T_CN; + + machine_menu.TemperatureConfTitle = TEMPERATURE_CONF_TITLE_T_CN; + machine_menu.NozzleConf = NOZZLE_CONF_T_CN; + machine_menu.HotBedConf = HOTBED_CONF_T_CN; + machine_menu.PreheatTemperConf = PREHEAT_TEMPER_T_CN; + + machine_menu.NozzleConfTitle = NOZZLE_CONF_TITLE_T_CN; + machine_menu.NozzleCnt = NOZZLECNT_T_CN; + machine_menu.NozzleType = NOZZLE_TYPE_T_CN; + machine_menu.NozzleAdjustType = NOZZLE_ADJUST_TYPE_T_CN; + machine_menu.NozzleMinTemperature = NOZZLE_MIN_TEMPERATURE_T_CN; + machine_menu.NozzleMaxTemperature = NOZZLE_MAX_TEMPERATURE_T_CN; + machine_menu.Extrude_Min_Temper = EXTRUD_MIN_TEMPER_T_CN; + + machine_menu.HotbedConfTitle = HOTBED_CONF_TITLE_T_CN; + machine_menu.HotbedAjustType = HOTBED_ADJUST_T_CN; + machine_menu.HotbedMinTemperature = HOTBED_MIN_TEMPERATURE_T_CN; + machine_menu.HotbedMaxTemperature = HOTBED_MAX_TEMPERATURE_T_CN; + + machine_menu.MotorConfTitle = MOTOR_CONF_TITLE_T_CN; + machine_menu.MaxFeedRateConf = MAXFEEDRATE_CONF_T_CN; + machine_menu.AccelerationConf = ACCELERATION_CONF_T_CN; + machine_menu.JerkConf = JERKCONF_T_CN; + machine_menu.StepsConf = STEPSCONF_T_CN; + machine_menu.TMCcurrentConf = TMC_CURRENT_T_CN; + machine_menu.TMCStepModeConf = TMC_STEP_MODE_T_CN; + machine_menu.MotorDirConf = MOTORDIRCONF_T_CN; + machine_menu.HomeFeedRateConf = HOMEFEEDRATECONF_T_CN; + machine_menu.PausePosition = PAUSE_POSITION_T_CN; + machine_menu.WifiSettings = WIFI_SETTINGS_T_CN; + machine_menu.HomingSensitivityConf = HOMING_SENSITIVITY_CONF_T_CN; + machine_menu.EncoderSettings = ENCODER_SETTINGS_T_CN; + + machine_menu.MaxFeedRateConfTitle = MAXFEEDRATE_CONF_TITLE_T_CN; + machine_menu.XMaxFeedRate = X_MAXFEEDRATE_T_CN; + machine_menu.YMaxFeedRate = Y_MAXFEEDRATE_T_CN; + machine_menu.ZMaxFeedRate = Z_MAXFEEDRATE_T_CN; + machine_menu.E0MaxFeedRate = E0_MAXFEEDRATE_T_CN; + machine_menu.E1MaxFeedRate = E1_MAXFEEDRATE_T_CN; + + machine_menu.AccelerationConfTitle = ACCELERATION_CONF_TITLE_T_CN; + machine_menu.PrintAcceleration = PRINT_ACCELERATION_T_CN; + machine_menu.RetractAcceleration = RETRACT_ACCELERATION_T_CN; + machine_menu.TravelAcceleration = TRAVEL_ACCELERATION_T_CN; + machine_menu.X_Acceleration = X_ACCELERATION_T_CN; + machine_menu.Y_Acceleration = Y_ACCELERATION_T_CN; + machine_menu.Z_Acceleration = Z_ACCELERATION_T_CN; + machine_menu.E0_Acceleration = E0_ACCELERATION_T_CN; + machine_menu.E1_Acceleration = E1_ACCELERATION_T_CN; + + machine_menu.JerkConfTitle = JERK_CONF_TITLE_T_CN; + machine_menu.X_Jerk = X_JERK_T_CN; + machine_menu.Y_Jerk = Y_JERK_T_CN; + machine_menu.Z_Jerk = Z_JERK_T_CN; + machine_menu.E_Jerk = E_JERK_T_CN; + + machine_menu.StepsConfTitle = STEPS_CONF_TITLE_T_CN; + machine_menu.X_Steps = X_STEPS_T_CN; + machine_menu.Y_Steps = Y_STEPS_T_CN; + machine_menu.Z_Steps = Z_STEPS_T_CN; + machine_menu.E0_Steps = E0_STEPS_T_CN; + machine_menu.E1_Steps = E1_STEPS_T_CN; + + machine_menu.TmcCurrentConfTitle = TMC_CURRENT_CONF_TITLE_T_CN; + machine_menu.X_Current = X_TMC_CURRENT_T_CN; + machine_menu.Y_Current = Y_TMC_CURRENT_T_CN; + machine_menu.Z_Current = Z_TMC_CURRENT_T_CN; + machine_menu.E0_Current = E0_TMC_CURRENT_T_CN; + machine_menu.E1_Current = E1_TMC_CURRENT_T_CN; + + machine_menu.TmcStepModeConfTitle = TMC_MODE_CONF_TITLE_T_CN; + machine_menu.X_StepMode = X_TMC_MODE_T_CN; + machine_menu.Y_StepMode = Y_TMC_MODE_T_CN; + machine_menu.Z_StepMode = Z_TMC_MODE_T_CN; + machine_menu.E0_StepMode = E0_TMC_MODE_T_CN; + machine_menu.E1_StepMode = E1_TMC_MODE_T_CN; + + machine_menu.MotorDirConfTitle = MOTORDIR_CONF_TITLE_T_CN; + machine_menu.X_MotorDir = X_MOTORDIR_T_CN; + machine_menu.Y_MotorDir = Y_MOTORDIR_T_CN; + machine_menu.Z_MotorDir = Z_MOTORDIR_T_CN; + machine_menu.E0_MotorDir = E0_MOTORDIR_T_CN; + machine_menu.E1_MotorDir = E1_MOTORDIR_T_CN; + machine_menu.Invert_0 = INVERT_P_T_CN; + machine_menu.Invert_1 = INVERT_N_T_CN; + + machine_menu.HomeFeedRateConfTitle = HOMEFEEDRATE_CONF_TITLE_T_CN; + machine_menu.XY_HomeFeedRate = X_HOMESPEED_T_CN; + machine_menu.Z_HomeFeedRate = Z_HOMESPEED_T_CN; + + machine_menu.AdvancedConfTitle = ADVANCED_CONF_TITLE_T_CN; + machine_menu.PwrOffDection = PWROFF_DECTION_T_CN; + machine_menu.PwrOffAfterPrint = PWROFF_AFTER_PRINT_T_CN; + machine_menu.HaveUps = HAVE_UPS_T_CN; + machine_menu.Z2andZ2Endstop = Z2_AND_Z2ENDSTOP_CONF_T_CN; + machine_menu.EnablePinsInvert = ENABLE_PINS_CONF_T_CN; + + machine_menu.Z2ConfTitle = Z2_AND_Z2ENDSTOP_CONF_TITLE_T_CN; + machine_menu.Z2Enable = Z2_ENABLE_T_CN; + machine_menu.Z2EndstopEnable = Z2_ENDSTOP_T_CN; + machine_menu.Z2Port = Z2_PORT_T_CN; + + machine_menu.EnablePinsInvertTitle = ENABLE_PINS_CONF_TITLE_T_CN; + machine_menu.XInvert = X_ENABLE_PINS_INVERT_T_CN; + machine_menu.YInvert = Y_ENABLE_PINS_INVERT_T_CN; + machine_menu.ZInvert = Z_ENABLE_PINS_INVERT_T_CN; + machine_menu.EInvert = E_ENABLE_PINS_INVERT_T_CN; + + machine_menu.key_back = KEY_BACK_T_CN; + machine_menu.key_reset = KEY_REST_T_CN; + machine_menu.key_confirm = KEY_CONFIRM_T_CN; + + machine_menu.PausePosText = PAUSE_POSITION_T_CN; + machine_menu.xPos = PAUSE_POSITION_X_T_CN; + machine_menu.yPos = PAUSE_POSITION_Y_T_CN; + machine_menu.zPos = PAUSE_POSITION_Z_T_CN; + + machine_menu.WifiConfTitle = WIFI_SETTINGS_TITLE_T_CN; + machine_menu.wifiMode = WIFI_SETTINGS_MODE_T_CN; + machine_menu.wifiName = WIFI_SETTINGS_NAME_T_CN; + machine_menu.wifiPassWord = WIFI_SETTINGS_PASSWORD_T_CN; + machine_menu.wifiCloud = WIFI_SETTINGS_CLOUD_T_CN; + machine_menu.wifiConfig = WIFI_SETTINGS_CONFIG_T_CN; + machine_menu.wifiEdit = WIFI_SETTINGS_EDIT_T_CN; + machine_menu.wifiConfigTips = WIFI_CONFIG_TIPS_T_CN; + + machine_menu.OffsetConfTitle = OFFSET_TITLE_T_CN; + machine_menu.Xoffset = OFFSET_X_T_CN; + machine_menu.Yoffset = OFFSET_Y_T_CN; + machine_menu.Zoffset = OFFSET_Z_T_CN; + + machine_menu.LevelingTouchmiConf = LEVELING_TOUCHMI_T_CN; + machine_menu.TouchmiInit = TM_INIT_T_CN; + machine_menu.TouchmiOffsetpos = TM_ZOFFSETPOS_T_CN; + machine_menu.TouchmiOffsetneg = TM_ZOFFSETNEG_T_CN; + machine_menu.TouchmiSave = TM_SAVE_T_CN; + machine_menu.TouchmiTest = TM_TEST_T_CN; + + machine_menu.BLTouchLevelingConfTitle = BLTOUCH_LEVELING_TITTLE_T_CN; + machine_menu.BLTouchLevelingConf = BLTOUCH_LEVELING_T_CN; + machine_menu.BLTouchInit = BLTOUCH_INIT_T_CN; + machine_menu.BLTouchOffsetpos = BLTOUCH_ZOFFSETPOS_T_CN; + machine_menu.BLTouchOffsetneg = BLTOUCH_ZOFFSETNEG_T_CN; + machine_menu.BLTouchSave = BLTOUCH_SAVE_T_CN; + machine_menu.BLTouchTest = BLTOUCH_TEST_T_CN; + + machine_menu.HomingSensitivityConfTitle = HOMING_SENSITIVITY_CONF_TITLE_T_CN; + machine_menu.X_Sensitivity = X_SENSITIVITY_T_CN; + machine_menu.Y_Sensitivity = Y_SENSITIVITY_T_CN; + machine_menu.Z_Sensitivity = Z_SENSITIVITY_T_CN; + machine_menu.Z2_Sensitivity = Z2_SENSITIVITY_T_CN; + + machine_menu.EncoderConfTitle = ENCODER_CONF_TITLE_T_CN; + machine_menu.EncoderConfText = ENCODER_CONF_TEXT_T_CN; + } + else { + MachinePara_menu.title = MACHINE_PARA_TITLE_EN; + MachinePara_menu.MachineSetting = MACHINE_TYPE_CNOFIG_EN; + MachinePara_menu.MotorSetting = MOTOR_CONFIG_EN; + MachinePara_menu.leveling = MACHINE_LEVELING_CONFIG_EN; + MachinePara_menu.AdvanceSetting = ADVANCE_CONFIG_EN; + + machine_menu.default_value = DEFAULT_EN; + machine_menu.next = NEXT_EN; + machine_menu.previous = PREVIOUS_EN; + + machine_menu.MachineConfigTitle = MACHINE_CONFIG_TITLE_EN; + machine_menu.MachineType = MACHINE_TYPE_EN; + machine_menu.Stroke = MACHINE_STROKE_EN; + machine_menu.HomeDir = MACHINE_HOMEDIR_EN; + machine_menu.EndStopType = MACHINE_ENDSTOP_TYPE_EN; + machine_menu.FilamentConf = MACHINE_FILAMENT_CONFIG_EN; + + machine_menu.MachineTypeConfTitle = MACHINE_TYPE_CONFIG_TITLE_EN; + machine_menu.xyz = MACHINE_TYPE_XYZ_EN; + machine_menu.delta = MACHINE_TYPE_DELTA_EN; + machine_menu.corexy = MACHINE_TYPE_COREXY_EN; + + machine_menu.StrokeConfTitle = MACHINE_STROKE_CONF_TITLE_EN; + machine_menu.xStroke = X_MAX_LENGTH_EN; + machine_menu.yStroke = Y_MAX_LENGTH_EN; + machine_menu.zStroke = Z_MAX_LENGTH_EN; + + machine_menu.xmin = X_MIN_LENGTH_EN; + machine_menu.ymin = Y_MIN_LENGTH_EN; + machine_menu.zmin = Z_MIN_LENGTH_EN; + + machine_menu.HomeDirConfTitle = HOME_DIR_CONF_TITLE_EN; + machine_menu.xHomeDir = HOME_DIR_X_EN; + machine_menu.yHomeDir = HOME_DIR_Y_EN; + machine_menu.zHomeDir = HOME_DIR_Z_EN; + machine_menu.min = HOME_MIN_EN; + machine_menu.max = HOME_MAX_EN; + + machine_menu.EndstopConfTitle = ENDSTOP_CONF_TITLE_EN; + machine_menu.xEndstop_min = MIN_ENDSTOP_X_EN; + machine_menu.yEndstop_min = MIN_ENDSTOP_Y_EN; + machine_menu.zEndstop_min = MIN_ENDSTOP_Z_EN; + machine_menu.xEndstop_max = MAX_ENDSTOP_X_EN; + machine_menu.yEndstop_max = MAX_ENDSTOP_Y_EN; + machine_menu.zEndstop_max = MAX_ENDSTOP_Z_EN; + machine_menu.FilamentEndstop = ENDSTOP_FIL_EN; + machine_menu.LevelingEndstop = ENDSTOP_LEVEL_EN; + machine_menu.opened = ENDSTOP_OPENED_EN; + machine_menu.closed = ENDSTOP_CLOSED_EN; + + machine_menu.FilamentConfTitle = FILAMENT_CONF_TITLE_EN; + machine_menu.InLength = FILAMENT_IN_LENGTH_EN; + machine_menu.InSpeed = FILAMENT_IN_SPEED_EN; + machine_menu.FilamentTemperature = FILAMENT_TEMPERATURE_EN; + machine_menu.OutLength = FILAMENT_OUT_LENGTH_EN; + machine_menu.OutSpeed = FILAMENT_OUT_SPEED_EN; + + machine_menu.LevelingParaConfTitle = LEVELING_CONF_TITLE_EN; + machine_menu.LevelingParaConf = LEVELING_PARA_CONF_EN; + machine_menu.LevelingManuPosConf = LEVELING_MANUAL_POS_EN; + machine_menu.LevelingAutoCommandConf = LEVELING_AUTO_COMMAND_EN; + machine_menu.LevelingAutoZoffsetConf = LEVELING_AUTO_ZOFFSET_EN; + + machine_menu.LevelingSubConfTitle = LEVELING_PARA_CONF_TITLE_EN; + machine_menu.AutoLevelEnable = AUTO_LEVELING_ENABLE_EN; + machine_menu.BLtouchEnable = BLTOUCH_LEVELING_ENABLE_EN; + machine_menu.ProbePort = PROBE_PORT_EN; + machine_menu.ProbeXoffset = PROBE_X_OFFSET_EN; + machine_menu.ProbeYoffset = PROBE_Y_OFFSET_EN; + machine_menu.ProbeZoffset = PROBE_Z_OFFSET_EN; + machine_menu.ProbeXYspeed = PROBE_XY_SPEED_EN; + machine_menu.ProbeZspeed = PROBE_Z_SPEED_EN; + machine_menu.enable = ENABLE_EN; + machine_menu.disable = DISABLE_EN; + machine_menu.locked = LOCKED_EN; + machine_menu.z_min = Z_MIN_EN; + machine_menu.z_max = Z_MAX_EN; + + machine_menu.LevelingSubDeltaConfTitle = DELTA_LEVEL_CONF_TITLE_EN; + machine_menu.MachineRadius = DELTA_MACHINE_RADIUS_EN; + machine_menu.DiagonalRod = DELTA_DIAGONAL_ROD_EN; + machine_menu.PrintableRadius = DELTA_PRINT_RADIUS_EN; + machine_menu.DeltaHeight = DELTA_HEIGHT_EN; + machine_menu.SmoothRodOffset = SMOOTH_ROD_OFFSET_EN; + machine_menu.EffectorOffset = EFFECTOR_OFFSET_EN; + machine_menu.CalibrationRadius = CALIBRATION_RADIUS_EN; + + machine_menu.LevelingSubXYZConfTitle = XYZ_LEVEL_CONF_TITLE_EN; + + machine_menu.TemperatureConfTitle = TEMPERATURE_CONF_TITLE_EN; + machine_menu.NozzleConf = NOZZLE_CONF_EN; + machine_menu.HotBedConf = HOTBED_CONF_EN; + machine_menu.PreheatTemperConf = PREHEAT_TEMPER_EN; + + machine_menu.NozzleConfTitle = NOZZLE_CONF_TITLE_EN; + machine_menu.NozzleCnt = NOZZLECNT_EN; + machine_menu.NozzleType = NOZZLE_TYPE_EN; + machine_menu.NozzleAdjustType = NOZZLE_ADJUST_TYPE_EN; + machine_menu.NozzleMinTemperature = NOZZLE_MIN_TEMPERATURE_EN; + machine_menu.NozzleMaxTemperature = NOZZLE_MAX_TEMPERATURE_EN; + machine_menu.Extrude_Min_Temper = EXTRUD_MIN_TEMPER_EN; + + machine_menu.HotbedEnable = HOTBED_ENABLE_EN; + machine_menu.HotbedConfTitle = HOTBED_CONF_TITLE_EN; + machine_menu.HotbedAjustType = HOTBED_ADJUST_EN; + machine_menu.HotbedMinTemperature = HOTBED_MIN_TEMPERATURE_EN; + machine_menu.HotbedMaxTemperature = HOTBED_MAX_TEMPERATURE_EN; + + machine_menu.MotorConfTitle = MOTOR_CONF_TITLE_EN; + machine_menu.MaxFeedRateConf = MAXFEEDRATE_CONF_EN; + machine_menu.AccelerationConf = ACCELERATION_CONF_EN; + machine_menu.JerkConf = JERKCONF_EN; + machine_menu.StepsConf = STEPSCONF_EN; + machine_menu.TMCcurrentConf = TMC_CURRENT_EN; + machine_menu.TMCStepModeConf = TMC_STEP_MODE_EN; + machine_menu.MotorDirConf = MOTORDIRCONF_EN; + machine_menu.HomeFeedRateConf = HOMEFEEDRATECONF_EN; + machine_menu.PausePosition = PAUSE_POSITION_EN; + machine_menu.WifiSettings = WIFI_SETTINGS_EN; + machine_menu.HomingSensitivityConf = HOMING_SENSITIVITY_CONF_EN; + machine_menu.EncoderSettings = ENCODER_SETTINGS_EN; + + machine_menu.MaxFeedRateConfTitle = MAXFEEDRATE_CONF_TITLE_EN; + machine_menu.XMaxFeedRate = X_MAXFEEDRATE_EN; + machine_menu.YMaxFeedRate = Y_MAXFEEDRATE_EN; + machine_menu.ZMaxFeedRate = Z_MAXFEEDRATE_EN; + machine_menu.E0MaxFeedRate = E0_MAXFEEDRATE_EN; + machine_menu.E1MaxFeedRate = E1_MAXFEEDRATE_EN; + + machine_menu.AccelerationConfTitle = ACCELERATION_CONF_TITLE_EN; + machine_menu.PrintAcceleration = PRINT_ACCELERATION_EN; + machine_menu.RetractAcceleration = RETRACT_ACCELERATION_EN; + machine_menu.TravelAcceleration = TRAVEL_ACCELERATION_EN; + machine_menu.X_Acceleration = X_ACCELERATION_EN; + machine_menu.Y_Acceleration = Y_ACCELERATION_EN; + machine_menu.Z_Acceleration = Z_ACCELERATION_EN; + machine_menu.E0_Acceleration = E0_ACCELERATION_EN; + machine_menu.E1_Acceleration = E1_ACCELERATION_EN; + + machine_menu.JerkConfTitle = JERK_CONF_TITLE_EN; + machine_menu.X_Jerk = X_JERK_EN; + machine_menu.Y_Jerk = Y_JERK_EN; + machine_menu.Z_Jerk = Z_JERK_EN; + machine_menu.E_Jerk = E_JERK_EN; + + machine_menu.StepsConfTitle = STEPS_CONF_TITLE_EN; + machine_menu.X_Steps = X_STEPS_EN; + machine_menu.Y_Steps = Y_STEPS_EN; + machine_menu.Z_Steps = Z_STEPS_EN; + machine_menu.E0_Steps = E0_STEPS_EN; + machine_menu.E1_Steps = E1_STEPS_EN; + + machine_menu.TmcCurrentConfTitle = TMC_CURRENT_CONF_TITLE_EN; + machine_menu.X_Current = X_TMC_CURRENT_EN; + machine_menu.Y_Current = Y_TMC_CURRENT_EN; + machine_menu.Z_Current = Z_TMC_CURRENT_EN; + machine_menu.E0_Current = E0_TMC_CURRENT_EN; + machine_menu.E1_Current = E1_TMC_CURRENT_EN; + + machine_menu.TmcStepModeConfTitle = TMC_MODE_CONF_TITLE_EN; + machine_menu.X_StepMode = X_TMC_MODE_EN; + machine_menu.Y_StepMode = Y_TMC_MODE_EN; + machine_menu.Z_StepMode = Z_TMC_MODE_EN; + machine_menu.E0_StepMode = E0_TMC_MODE_EN; + machine_menu.E1_StepMode = E1_TMC_MODE_EN; + + machine_menu.MotorDirConfTitle = MOTORDIR_CONF_TITLE_EN; + machine_menu.X_MotorDir = X_MOTORDIR_EN; + machine_menu.Y_MotorDir = Y_MOTORDIR_EN; + machine_menu.Z_MotorDir = Z_MOTORDIR_EN; + machine_menu.E0_MotorDir = E0_MOTORDIR_EN; + machine_menu.E1_MotorDir = E1_MOTORDIR_EN; + machine_menu.Invert_0 = INVERT_P_EN; + machine_menu.Invert_1 = INVERT_N_EN; + + machine_menu.HomeFeedRateConfTitle = HOMEFEEDRATE_CONF_TITLE_EN; + machine_menu.XY_HomeFeedRate = X_HOMESPEED_EN; + machine_menu.Z_HomeFeedRate = Z_HOMESPEED_EN; + + machine_menu.AdvancedConfTitle = ADVANCED_CONF_TITLE_EN; + machine_menu.PwrOffDection = PWROFF_DECTION_EN; + machine_menu.PwrOffAfterPrint = PWROFF_AFTER_PRINT_EN; + machine_menu.HaveUps = HAVE_UPS_EN; + machine_menu.Z2andZ2Endstop = Z2_AND_Z2ENDSTOP_CONF_EN; + machine_menu.EnablePinsInvert = ENABLE_PINS_CONF_EN; + + machine_menu.Z2ConfTitle = Z2_AND_Z2ENDSTOP_CONF_TITLE_EN; + machine_menu.Z2Enable = Z2_ENABLE_EN; + machine_menu.Z2EndstopEnable = Z2_ENDSTOP_EN; + machine_menu.Z2Port = Z2_PORT_EN; + + machine_menu.EnablePinsInvertTitle = ENABLE_PINS_CONF_TITLE_EN; + machine_menu.XInvert = X_ENABLE_PINS_INVERT_EN; + machine_menu.YInvert = Y_ENABLE_PINS_INVERT_EN; + machine_menu.ZInvert = Z_ENABLE_PINS_INVERT_EN; + machine_menu.EInvert = E_ENABLE_PINS_INVERT_EN; + + machine_menu.key_back = KEY_BACK_EN; + machine_menu.key_reset = KEY_REST_EN; + machine_menu.key_confirm = KEY_CONFIRM_EN; + // + machine_menu.high_level = MOTOR_EN_HIGH_LEVEL_EN; + machine_menu.low_level = MOTOR_EN_LOW_LEVEL_EN; + + machine_menu.PausePosText = PAUSE_POSITION_EN; + machine_menu.xPos = PAUSE_POSITION_X_EN; + machine_menu.yPos = PAUSE_POSITION_Y_EN; + machine_menu.zPos = PAUSE_POSITION_Z_EN; + machine_menu.WifiConfTitle = WIFI_SETTINGS_TITLE_EN; + machine_menu.wifiMode = WIFI_SETTINGS_MODE_EN; + machine_menu.wifiName = WIFI_SETTINGS_NAME_EN; + machine_menu.wifiPassWord = WIFI_SETTINGS_PASSWORD_EN; + machine_menu.wifiCloud = WIFI_SETTINGS_CLOUD_EN; + machine_menu.wifiConfig = WIFI_SETTINGS_CONFIG_EN; + machine_menu.wifiEdit = WIFI_SETTINGS_EDIT_EN; + machine_menu.wifiConfigTips = WIFI_CONFIG_TIPS_EN; + + machine_menu.OffsetConfTitle = OFFSET_TITLE_EN; + machine_menu.Xoffset = OFFSET_X_EN; + machine_menu.Yoffset = OFFSET_Y_EN; + machine_menu.Zoffset = OFFSET_Z_EN; + + machine_menu.LevelingTouchmiConf = LEVELING_TOUCHMI_EN; + machine_menu.TouchmiInit = TM_INIT_EN; + machine_menu.TouchmiOffsetpos = TM_ZOFFSETPOS_EN; + machine_menu.TouchmiOffsetneg = TM_ZOFFSETNEG_EN; + machine_menu.TouchmiSave = TM_SAVE_EN; + machine_menu.TouchmiTest = TM_TEST_EN; + + machine_menu.BLTouchLevelingConfTitle = BLTOUCH_LEVELING_TITTLE_EN; + machine_menu.BLTouchLevelingConf = BLTOUCH_LEVELING_EN; + machine_menu.BLTouchInit = BLTOUCH_INIT_EN; + machine_menu.BLTouchOffsetpos = BLTOUCH_ZOFFSETPOS_EN; + machine_menu.BLTouchOffsetneg = BLTOUCH_ZOFFSETNEG_EN; + machine_menu.BLTouchSave = BLTOUCH_SAVE_EN; + machine_menu.BLTouchTest = BLTOUCH_TEST_EN; + + machine_menu.HomingSensitivityConfTitle = HOMING_SENSITIVITY_CONF_TITLE_EN; + machine_menu.X_Sensitivity = X_SENSITIVITY_EN; + machine_menu.Y_Sensitivity = Y_SENSITIVITY_EN; + machine_menu.Z_Sensitivity = Z_SENSITIVITY_EN; + machine_menu.Z2_Sensitivity = Z2_SENSITIVITY_EN; + + machine_menu.EncoderConfTitle = ENCODER_CONF_TITLE_EN; + machine_menu.EncoderConfText = ENCODER_CONF_TEXT_EN; + } +} + +void disp_language_init() { + preheat_menu.value_state = TEXT_VALUE; + preheat_menu.step_1c = TEXT_1C; + preheat_menu.step_5c = TEXT_5C; + preheat_menu.step_10c = TEXT_10C; + + move_menu.x_add = AXIS_X_ADD_TEXT; + move_menu.x_dec = AXIS_X_DEC_TEXT; + move_menu.y_add = AXIS_Y_ADD_TEXT; + move_menu.y_dec = AXIS_Y_DEC_TEXT; + move_menu.z_add = AXIS_Z_ADD_TEXT; + move_menu.z_dec = AXIS_Z_DEC_TEXT; + + move_menu.step_001mm = TEXT_001MM; + move_menu.step_005mm = TEXT_005MM; + move_menu.step_01mm = TEXT_01MM; + move_menu.step_1mm = TEXT_1MM; + move_menu.step_10mm = TEXT_10MM; + + home_menu.home_x = HOME_X_TEXT; + home_menu.home_y = HOME_Y_TEXT; + home_menu.home_z = HOME_Z_TEXT; + home_menu.home_all = HOME_ALL_TEXT; + + extrude_menu.temp_value = TEXT_VALUE_T; + extrude_menu.count_value_mm = TEXT_VALUE_mm; + extrude_menu.count_value_cm = TEXT_VALUE_cm; + extrude_menu.count_value_m = TEXT_VALUE_m; + extrude_menu.step_1mm = EXTRUDE_1MM_TEXT; + extrude_menu.step_5mm = EXTRUDE_5MM_TEXT; + extrude_menu.step_10mm = EXTRUDE_10MM_TEXT; + + fan_menu.full = FAN_OPEN_TEXT; + fan_menu.half = FAN_HALF_TEXT; + fan_menu.off = FAN_CLOSE_TEXT; + + speed_menu.step_1percent = STEP_1PERCENT; + speed_menu.step_5percent = STEP_5PERCENT; + speed_menu.step_10percent = STEP_10PERCENT; + + language_menu.chinese_s = LANGUAGE_S_CN; + language_menu.chinese_t = LANGUAGE_T_CN; + language_menu.english = LANGUAGE_EN; + language_menu.russian = LANGUAGE_RU; + language_menu.spanish = LANGUAGE_SP; + language_menu.german = LANGUAGE_GE; + language_menu.japan = LANGUAGE_JP; + language_menu.korean = LANGUAGE_KR; + language_menu.portuguese = LANGUAGE_PR; + language_menu.italy = LANGUAGE_IT; + language_menu.brazil = LANGUAGE_BR; + language_menu.french = LANGUAGE_FR; + + about_menu.type_name = ABOUT_TYPE_TEXT; + about_menu.firmware_v = ABOUT_VERSION_TEXT; + + wifi_menu.ip = WIFI_IP_TEXT; + wifi_menu.wifi = WIFI_NAME_TEXT; + wifi_menu.key = WIFI_KEY_TEXT; + wifi_menu.state_ap = WIFI_STATE_AP_TEXT; + wifi_menu.state_sta = WIFI_STATE_STA_TEXT; + wifi_menu.connected = WIFI_CONNECTED_TEXT; + wifi_menu.disconnected = WIFI_DISCONNECTED_TEXT; + wifi_menu.exception = WIFI_EXCEPTION_TEXT; + + printing_menu.temp1 = TEXT_VALUE; + printing_menu.temp2 = TEXT_VALUE; + printing_menu.bed_temp = TEXT_VALUE; + + filament_menu.stat_temp = TEXT_VALUE; + + machine_menu.key_0 = KEYBOARD_KEY0_EN; + machine_menu.key_1 = KEYBOARD_KEY1_EN; + machine_menu.key_2 = KEYBOARD_KEY2_EN; + machine_menu.key_3 = KEYBOARD_KEY3_EN; + machine_menu.key_4 = KEYBOARD_KEY4_EN; + machine_menu.key_5 = KEYBOARD_KEY5_EN; + machine_menu.key_6 = KEYBOARD_KEY6_EN; + machine_menu.key_7 = KEYBOARD_KEY7_EN; + machine_menu.key_8 = KEYBOARD_KEY8_EN; + machine_menu.key_9 = KEYBOARD_KEY9_EN; + machine_menu.key_point = KEYBOARD_KEY_POINT_EN; + machine_menu.negative = KEYBOARD_KEY_NEGATIVE_EN; + // wifi-list + #if ENABLED(MKS_WIFI_MODULE) + list_menu.title = TEXT_WIFI_MENU_TITLE_EN; + list_menu.file_pages = FILE_PAGES_EN; + + // tips + tips_menu.joining = TEXT_WIFI_JOINING_EN; + tips_menu.failedJoin = TEXT_WIFI_FAILED_JOIN_EN; + tips_menu.wifiConected = TEXT_WIFI_WIFI_CONECTED_EN; + #endif + machine_setting_disp(); + + operation_menu.babystep = TEXT_BABY_STEP_EN; + + switch (gCfgItems.language) { + case LANG_SIMPLE_CHINESE: + common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_CN; + common_menu.text_back = BACK_TEXT_CN; + common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_CN; + common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_CN; + common_menu.print_special_title = PRINTING_GBK; + common_menu.pause_special_title = PRINTING_PAUSE_GBK; + common_menu.operate_special_title = PRINTING_OPERATION_GBK; + // + main_menu.title = TITLE_READYPRINT_CN; + main_menu.preheat = PREHEAT_TEXT_CN; + main_menu.move = MOVE_TEXT_CN; + main_menu.home = HOME_TEXT_CN; + main_menu.print = PRINT_TEXT_CN; + main_menu.extrude = EXTRUDE_TEXT_CN; + main_menu.leveling = LEVELING_TEXT_CN; + main_menu.autoleveling = AUTO_LEVELING_TEXT_CN; + main_menu.fan = FAN_TEXT_CN; + main_menu.set = SET_TEXT_CN; + main_menu.more = MORE_TEXT_CN; + main_menu.tool = TOOL_TEXT_CN; + // TOOL + tool_menu.title = TOOL_TEXT_CN; + tool_menu.preheat = TOOL_PREHEAT_CN; + tool_menu.extrude = TOOL_EXTRUDE_CN; + tool_menu.move = TOOL_MOVE_CN; + tool_menu.home = TOOL_HOME_CN; + tool_menu.leveling = TOOL_LEVELING_CN; + tool_menu.autoleveling = TOOL_AUTO_LEVELING_CN; + tool_menu.filament = TOOL_FILAMENT_CN; + tool_menu.more = TOOL_MORE_CN; + // + preheat_menu.adjust_title = TITLE_ADJUST_CN; + preheat_menu.title = TITLE_PREHEAT_CN; + preheat_menu.add = ADD_TEXT_CN; + preheat_menu.dec = DEC_TEXT_CN; + preheat_menu.ext1 = EXTRUDER_1_TEXT_CN; + preheat_menu.ext2 = EXTRUDER_2_TEXT_CN; + preheat_menu.hotbed = HEATBED_TEXT_CN; + preheat_menu.off = CLOSE_TEXT_CN; + + preheat_menu.value_state = TEXT_VALUE_CN; + preheat_menu.step_1c = TEXT_1C_CN; + preheat_menu.step_5c = TEXT_5C_CN; + preheat_menu.step_10c = TEXT_10C_CN; + // + move_menu.title = MOVE_TEXT_CN; + // + home_menu.title = TITLE_HOME_CN; + home_menu.stopmove = HOME_STOPMOVE_CN; + // + file_menu.title = TITLE_CHOOSEFILE_CN; + file_menu.page_up = PAGE_UP_TEXT_CN; + file_menu.page_down = PAGE_DOWN_TEXT_CN; + file_menu.file_loading = FILE_LOADING_CN; + file_menu.no_file = NO_FILE_CN; + file_menu.no_file_and_check = NO_FILE_CN; + // + extrude_menu.title = TITLE_EXTRUDE_CN; + extrude_menu.in = EXTRUDER_IN_TEXT_CN; + extrude_menu.out = EXTRUDER_OUT_TEXT_CN; + extrude_menu.ext1 = EXTRUDER_1_TEXT_CN; + extrude_menu.ext2 = EXTRUDER_2_TEXT_CN; + extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_CN; + extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_CN; + extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_CN; + extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_CN; + extrude_menu.temp_value = EXTRUDE_TEXT_VALUE_T_CN; + // + leveling_menu.title = TITLE_LEVELING_CN; + leveling_menu.position1 = LEVELING_POINT1_TEXT_CN; + leveling_menu.position2 = LEVELING_POINT2_TEXT_CN; + leveling_menu.position3 = LEVELING_POINT3_TEXT_CN; + leveling_menu.position4 = LEVELING_POINT4_TEXT_CN; + leveling_menu.position5 = LEVELING_POINT5_TEXT_CN; + // + set_menu.title = TITLE_SET_CN; + set_menu.filesys = FILESYS_TEXT_CN; + set_menu.wifi = WIFI_TEXT_CN; + set_menu.about = ABOUT_TEXT_CN; + set_menu.fan = FAN_TEXT_CN; + set_menu.filament = FILAMENT_TEXT_CN; + set_menu.breakpoint = BREAK_POINT_TEXT_CN; + set_menu.motoroff = MOTOR_OFF_TEXT_CN; + set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_CN; + set_menu.language = LANGUAGE_TEXT_CN; + set_menu.shutdown = SHUTDOWN_TEXT_CN; + set_menu.machine_para = MACHINE_PARA_CN; + set_menu.eepromSet = EEPROM_SETTINGS_CN; + // + filesys_menu.title = TITLE_FILESYS_CN; + filesys_menu.sd_sys = SD_CARD_TEXT_CN; + filesys_menu.usb_sys = U_DISK_TEXT_CN; + // + more_menu.title = TITLE_MORE_CN; + #if ENABLED(USER_CMD_1_ENABLE) + more_menu.custom1 = MORE_CUSTOM1_TEXT_CN; + #endif + #if ENABLED(USER_CMD_2_ENABLE) + more_menu.custom2 = MORE_CUSTOM2_TEXT_CN; + #endif + #if ENABLED(USER_CMD_3_ENABLE) + more_menu.custom3 = MORE_CUSTOM3_TEXT_CN; + #endif + #if ENABLED(USER_CMD_4_ENABLE) + more_menu.custom4 = MORE_CUSTOM4_TEXT_CN; + #endif + #if ENABLED(USER_CMD_5_ENABLE) + more_menu.custom5 = MORE_CUSTOM5_TEXT_CN; + #endif + #if ENABLED(USER_CMD_6_ENABLE) + more_menu.custom6 = MORE_CUSTOM6_TEXT_CN; + #endif + #if ENABLED(USER_CMD_7_ENABLE) + more_menu.custom7 = MORE_CUSTOM7_TEXT_CN; + #endif + // WIFI + wifi_menu.title = WIFI_TEXT; + wifi_menu.cloud = CLOUD_TEXT_CN; + wifi_menu.reconnect = WIFI_RECONNECT_TEXT_CN; + // CLOUD + cloud_menu.title = TITLE_CLOUD_TEXT_CN; + cloud_menu.bind = CLOUD_BINDED_CN; + cloud_menu.binded = CLOUD_BINDED_CN; + cloud_menu.unbind = CLOUD_UNBIND_CN; + cloud_menu.unbinding = CLOUD_UNBINDED_CN; + cloud_menu.disconnected = CLOUD_DISCONNECTED_CN; + cloud_menu.unbinded = CLOUD_UNBINDED_CN; + cloud_menu.disable = CLOUD_DISABLE_CN; + // + about_menu.title = ABOUT_TEXT_CN; + about_menu.type = ABOUT_TYPE_TEXT_CN; + about_menu.version = ABOUT_VERSION_TEXT_CN; + about_menu.wifi = ABOUT_WIFI_TEXT_CN; + + // + fan_menu.title = FAN_TEXT_CN; + fan_menu.add = FAN_ADD_TEXT_CN; + fan_menu.dec = FAN_DEC_TEXT_CN; + fan_menu.state = FAN_TIPS1_TEXT_CN; + // + filament_menu.title = TITLE_FILAMENT_CN; + filament_menu.in = FILAMENT_IN_TEXT_CN; + filament_menu.out = FILAMENT_OUT_TEXT_CN; + filament_menu.ext1 = FILAMENT_EXT0_TEXT_CN; + filament_menu.ext2 = FILAMENT_EXT1_TEXT_CN; + filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_CN; + filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_CN; + filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_CN; + filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_CN; + filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_CN; + filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_CN; + filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_CN; + filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_CN; + filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_CN; + + + // + language_menu.title = TITLE_LANGUAGE_CN; + language_menu.next = PAGE_DOWN_TEXT_CN; + language_menu.up = PAGE_UP_TEXT_CN; + + // + printing_menu.title = TITLE_PRINTING_CN; + printing_menu.option = PRINTING_OPERATION_CN; + printing_menu.stop = PRINTING_STOP_CN; + printing_menu.pause = PRINTING_PAUSE_CN; + printing_menu.resume = PRINTING_RESUME_CN; + + // + operation_menu.title = TITLE_OPERATION_CN; + operation_menu.pause = PRINTING_PAUSE_CN; + operation_menu.stop = PRINTING_STOP_CN; + operation_menu.temp = PRINTING_TEMP_CN; + operation_menu.fan = FAN_TEXT_CN; + operation_menu.filament = FILAMENT_TEXT_CN; + operation_menu.extr = PRINTING_EXTRUDER_CN; + operation_menu.speed = PRINTING_CHANGESPEED_CN; + operation_menu.more = PRINTING_MORE_CN; + operation_menu.move = PRINTING_MOVE_CN; + operation_menu.auto_off = AUTO_SHUTDOWN_CN; + operation_menu.manual_off = MANUAL_SHUTDOWN_CN; + // + pause_menu.title = TITLE_PAUSE_CN; + pause_menu.resume = PRINTING_RESUME_CN; + pause_menu.stop = PRINTING_STOP_CN; + pause_menu.extrude = PRINTING_EXTRUDER_CN; + pause_menu.move = PRINTING_MOVE_CN; + pause_menu.filament = FILAMENT_TEXT_CN; + pause_menu.more = PRINTING_MORE_CN; + + // + speed_menu.title = PRINTING_CHANGESPEED_CN; + speed_menu.add = ADD_TEXT_CN; + speed_menu.dec = DEC_TEXT_CN; + speed_menu.move = MOVE_SPEED_CN; + speed_menu.extrude = EXTRUDER_SPEED_CN; + speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_CN; + speed_menu.move_speed = MOVE_SPEED_STATE_CN; + // + printing_more_menu.title = TITLE_MORE_CN; + printing_more_menu.fan = FAN_TEXT_CN; + printing_more_menu.auto_close = AUTO_SHUTDOWN_CN; + printing_more_menu.manual = MANUAL_SHUTDOWN_CN; + printing_more_menu.speed = PRINTING_CHANGESPEED_CN; + printing_more_menu.temp = PRINTING_TEMP_CN; + + print_file_dialog_menu.confirm = DIALOG_CONFIRM_CN; + print_file_dialog_menu.cancel = DIALOG_CANCLE_CN; + print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_CN; + print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_CN; + print_file_dialog_menu.retry = DIALOG_RETRY_CN; + print_file_dialog_menu.stop = DIALOG_STOP_CN; + print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_CN; + print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_CN; + + print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_CN; + print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_CN; + + print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_CN; + print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_CN; + print_file_dialog_menu.reprint = DIALOG_REPRINT_CN; + print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_CN; + print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_CN; + + pause_msg_menu.pausing = MESSAGE_PAUSING_CN; + pause_msg_menu.changing = MESSAGE_CHANGING_CN; + pause_msg_menu.unload = MESSAGE_UNLOAD_CN; + pause_msg_menu.waiting = MESSAGE_WAITING_CN; + pause_msg_menu.insert = MESSAGE_INSERT_CN; + pause_msg_menu.load = MESSAGE_LOAD_CN; + pause_msg_menu.purge = MESSAGE_PURGE_CN; + pause_msg_menu.resume = MESSAGE_RESUME_CN; + pause_msg_menu.heat = MESSAGE_HEAT_CN; + pause_msg_menu.heating = MESSAGE_HEATING_CN; + pause_msg_menu.option = MESSAGE_OPTION_CN; + pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_CN; + pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_CN; + eeprom_menu.title = EEPROM_SETTINGS_TITLE_CN; + eeprom_menu.store = EEPROM_SETTINGS_STORE_CN; + eeprom_menu.read = EEPROM_SETTINGS_READ_CN; + eeprom_menu.revert = EEPROM_SETTINGS_REVERT_CN; + eeprom_menu.storeTips = EEPROM_STORE_TIPS_CN; + eeprom_menu.readTips = EEPROM_READ_TIPS_CN; + eeprom_menu.revertTips = EEPROM_REVERT_TIPS_CN; + break; + + #if 1 + #if 1 + + case LANG_COMPLEX_CHINESE: + common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_T_CN; + common_menu.text_back = BACK_TEXT_T_CN; + common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_T_CN; + common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_T_CN; + common_menu.print_special_title = PRINTING_GBK; + common_menu.pause_special_title = PRINTING_PAUSE_GBK; + common_menu.operate_special_title = PRINTING_OPERATION_GBK; + // + main_menu.title = TITLE_READYPRINT_T_CN; + main_menu.preheat = PREHEAT_TEXT_T_CN; + main_menu.move = MOVE_TEXT_T_CN; + main_menu.home = HOME_TEXT_T_CN; + main_menu.print = PRINT_TEXT_T_CN; + main_menu.extrude = EXTRUDE_TEXT_T_CN; + main_menu.leveling = LEVELING_TEXT_T_CN; + main_menu.autoleveling = AUTO_LEVELING_TEXT_T_CN; + main_menu.fan = FAN_TEXT_T_CN; + main_menu.set = SET_TEXT_T_CN; + main_menu.more = MORE_TEXT_T_CN; + main_menu.tool = TOOL_TEXT_T_CN; + // TOOL + tool_menu.title = TOOL_TEXT_T_CN; + tool_menu.preheat = TOOL_PREHEAT_T_CN; + tool_menu.extrude = TOOL_EXTRUDE_T_CN; + tool_menu.move = TOOL_MOVE_T_CN; + tool_menu.home = TOOL_HOME_T_CN; + tool_menu.leveling = TOOL_LEVELING_T_CN; + tool_menu.autoleveling = TOOL_AUTO_LEVELING_T_CN; + tool_menu.filament = TOOL_FILAMENT_T_CN; + tool_menu.more = TOOL_MORE_T_CN; + // + preheat_menu.adjust_title = TITLE_ADJUST_T_CN; + preheat_menu.title = TITLE_PREHEAT_T_CN; + preheat_menu.add = ADD_TEXT_T_CN; + preheat_menu.dec = DEC_TEXT_T_CN; + preheat_menu.ext1 = EXTRUDER_1_TEXT_T_CN; + preheat_menu.ext2 = EXTRUDER_2_TEXT_T_CN; + preheat_menu.hotbed = HEATBED_TEXT_T_CN; + preheat_menu.off = CLOSE_TEXT_T_CN; + preheat_menu.value_state = TEXT_VALUE_T_CN; + preheat_menu.step_1c = TEXT_1C_T_CN; + preheat_menu.step_5c = TEXT_5C_T_CN; + preheat_menu.step_10c = TEXT_10C_T_CN; + // + move_menu.title = MOVE_TEXT_T_CN; + // + home_menu.title = TITLE_HOME_T_CN; + home_menu.stopmove = HOME_STOPMOVE_T_CN; + // + file_menu.title = TITLE_CHOOSEFILE_T_CN; + file_menu.page_up = PAGE_UP_TEXT_T_CN; + file_menu.page_down = PAGE_DOWN_TEXT_T_CN; + file_menu.file_loading = FILE_LOADING_T_CN; + file_menu.no_file = NO_FILE_T_CN; + file_menu.no_file_and_check = NO_FILE_T_CN; + // + extrude_menu.title = TITLE_EXTRUDE_T_CN; + extrude_menu.in = EXTRUDER_IN_TEXT_T_CN; + extrude_menu.out = EXTRUDER_OUT_TEXT_T_CN; + extrude_menu.ext1 = EXTRUDER_1_TEXT_T_CN; + extrude_menu.ext2 = EXTRUDER_2_TEXT_T_CN; + extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_T_CN; + extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_T_CN; + extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_T_CN; + extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_T_CN; + extrude_menu.temp_value = EXTRUDE_TEXT_VALUE_T_T_CN; + // + leveling_menu.title = TITLE_LEVELING_CN; + leveling_menu.position1 = LEVELING_POINT1_TEXT_T_CN; + leveling_menu.position2 = LEVELING_POINT2_TEXT_T_CN; + leveling_menu.position3 = LEVELING_POINT3_TEXT_T_CN; + leveling_menu.position4 = LEVELING_POINT4_TEXT_T_CN; + leveling_menu.position5 = LEVELING_POINT5_TEXT_T_CN; + // + set_menu.title = TITLE_SET_T_CN; + set_menu.filesys = FILESYS_TEXT_T_CN; + set_menu.wifi = WIFI_TEXT_T_CN; + set_menu.about = ABOUT_TEXT_T_CN; + set_menu.fan = FAN_TEXT_T_CN; + set_menu.filament = FILAMENT_TEXT_T_CN; + set_menu.breakpoint = BREAK_POINT_TEXT_T_CN; + set_menu.motoroff = MOTOR_OFF_TEXT_T_CN; + set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_T_CN; + set_menu.language = LANGUAGE_TEXT_T_CN; + set_menu.shutdown = SHUTDOWN_TEXT_T_CN; + set_menu.machine_para = MACHINE_PARA_T_CN; + set_menu.eepromSet = EEPROM_SETTINGS_T_CN; + filesys_menu.title = TITLE_FILESYS_T_CN; + filesys_menu.sd_sys = SD_CARD_TEXT_T_CN; + filesys_menu.usb_sys = U_DISK_TEXT_T_CN; + // + more_menu.title = TITLE_MORE_T_CN; + #if ENABLED(USER_CMD_1_ENABLE) + more_menu.custom1 = MORE_CUSTOM1_TEXT_T_CN; + #endif + #if ENABLED(USER_CMD_2_ENABLE) + more_menu.custom2 = MORE_CUSTOM2_TEXT_T_CN; + #endif + #if ENABLED(USER_CMD_3_ENABLE) + more_menu.custom3 = MORE_CUSTOM3_TEXT_T_CN; + #endif + #if ENABLED(USER_CMD_4_ENABLE) + more_menu.custom4 = MORE_CUSTOM4_TEXT_T_CN; + #endif + #if ENABLED(USER_CMD_5_ENABLE) + more_menu.custom5 = MORE_CUSTOM5_TEXT_T_CN; + #endif + #if ENABLED(USER_CMD_6_ENABLE) + more_menu.custom6 = MORE_CUSTOM6_TEXT_T_CN; + #endif + #if ENABLED(USER_CMD_7_ENABLE) + more_menu.custom7 = MORE_CUSTOM7_TEXT_T_CN; + #endif + // WIFI + wifi_menu.title = WIFI_TEXT; + wifi_menu.cloud = CLOUD_TEXT_T_CN; + wifi_menu.reconnect = WIFI_RECONNECT_TEXT_T_CN; + // CLOUD + cloud_menu.title = TITLE_CLOUD_TEXT_T_CN; + cloud_menu.bind = CLOUD_BINDED_T_CN; + cloud_menu.binded = CLOUD_BINDED_T_CN; + cloud_menu.unbind = CLOUD_UNBIND_T_CN; + cloud_menu.unbinding = CLOUD_UNBINDED_T_CN; + cloud_menu.disconnected = CLOUD_DISCONNECTED_T_CN; + cloud_menu.unbinded = CLOUD_UNBINDED_T_CN; + cloud_menu.disable = CLOUD_DISABLE_T_CN; + // + about_menu.title = ABOUT_TEXT_T_CN; + about_menu.type = ABOUT_TYPE_TEXT_T_CN; + about_menu.version = ABOUT_VERSION_TEXT_T_CN; + about_menu.wifi = ABOUT_WIFI_TEXT_T_CN; + + // + fan_menu.title = FAN_TEXT_T_CN; + fan_menu.add = FAN_ADD_TEXT_T_CN; + fan_menu.dec = FAN_DEC_TEXT_T_CN; + fan_menu.state = FAN_TIPS1_TEXT_T_CN; + // + filament_menu.title = TITLE_FILAMENT_T_CN; + filament_menu.in = FILAMENT_IN_TEXT_T_CN; + filament_menu.out = FILAMENT_OUT_TEXT_T_CN; + filament_menu.ext1 = FILAMENT_EXT0_TEXT_T_CN; + filament_menu.ext2 = FILAMENT_EXT1_TEXT_T_CN; + filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_T_CN; + filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_T_CN; + filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_T_CN; + filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_T_CN; + filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_T_CN; + filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_T_CN; + filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_T_CN; + filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_T_CN; + filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_T_CN; + + // + language_menu.title = TITLE_LANGUAGE_T_CN; + language_menu.next = PAGE_DOWN_TEXT_T_CN; + language_menu.up = PAGE_UP_TEXT_T_CN; + + // + printing_menu.title = TITLE_PRINTING_T_CN; + printing_menu.option = PRINTING_OPERATION_T_CN; + printing_menu.stop = PRINTING_STOP_T_CN; + printing_menu.pause = PRINTING_PAUSE_T_CN; + printing_menu.resume = PRINTING_RESUME_T_CN; + + // + operation_menu.title = TITLE_OPERATION_T_CN; + operation_menu.pause = PRINTING_PAUSE_T_CN; + operation_menu.stop = PRINTING_STOP_T_CN; + operation_menu.temp = PRINTING_TEMP_T_CN; + operation_menu.fan = FAN_TEXT_T_CN; + operation_menu.extr = PRINTING_EXTRUDER_T_CN; + operation_menu.speed = PRINTING_CHANGESPEED_T_CN; + operation_menu.filament = FILAMENT_TEXT_T_CN; + operation_menu.more = PRINTING_MORE_T_CN; + operation_menu.move = PRINTING_MOVE_T_CN; + operation_menu.auto_off = AUTO_SHUTDOWN_T_CN; + operation_menu.manual_off = MANUAL_SHUTDOWN_T_CN; + // + pause_menu.title = TITLE_PAUSE_T_CN; + pause_menu.resume = PRINTING_RESUME_T_CN; + pause_menu.stop = PRINTING_STOP_T_CN; + pause_menu.extrude = PRINTING_EXTRUDER_T_CN; + pause_menu.move = PRINTING_MOVE_T_CN; + pause_menu.filament = FILAMENT_TEXT_T_CN; + pause_menu.more = PRINTING_MORE_T_CN; + + // + speed_menu.title = PRINTING_CHANGESPEED_T_CN; + speed_menu.add = ADD_TEXT_T_CN; + speed_menu.dec = DEC_TEXT_T_CN; + speed_menu.move = MOVE_SPEED_T_CN; + speed_menu.extrude = EXTRUDER_SPEED_T_CN; + speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_T_CN; + speed_menu.move_speed = MOVE_SPEED_STATE_T_CN; + // + printing_more_menu.title = TITLE_MORE_T_CN; + printing_more_menu.fan = FAN_TEXT_T_CN; + printing_more_menu.auto_close = AUTO_SHUTDOWN_T_CN; + printing_more_menu.manual = MANUAL_SHUTDOWN_T_CN; + printing_more_menu.speed = PRINTING_CHANGESPEED_T_CN; + printing_more_menu.temp = PRINTING_TEMP_T_CN; + + print_file_dialog_menu.confirm = DIALOG_CONFIRM_T_CN; + print_file_dialog_menu.cancel = DIALOG_CANCLE_T_CN; + print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_T_CN; + print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_T_CN; + print_file_dialog_menu.retry = DIALOG_RETRY_T_CN; + print_file_dialog_menu.stop = DIALOG_STOP_T_CN; + print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_T_CN; + print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_T_CN; + + print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_T_CN; + print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_T_CN; + print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_T_CN; + print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_T_CN; + print_file_dialog_menu.reprint = DIALOG_REPRINT_T_CN; + print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_T_CN; + print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_T_CN; + + pause_msg_menu.pausing = MESSAGE_PAUSING_T_CN; + pause_msg_menu.changing = MESSAGE_CHANGING_T_CN; + pause_msg_menu.unload = MESSAGE_UNLOAD_T_CN; + pause_msg_menu.waiting = MESSAGE_WAITING_T_CN; + pause_msg_menu.insert = MESSAGE_INSERT_T_CN; + pause_msg_menu.load = MESSAGE_LOAD_T_CN; + pause_msg_menu.purge = MESSAGE_PURGE_T_CN; + pause_msg_menu.resume = MESSAGE_RESUME_T_CN; + pause_msg_menu.heat = MESSAGE_HEAT_T_CN; + pause_msg_menu.heating = MESSAGE_HEATING_T_CN; + pause_msg_menu.option = MESSAGE_OPTION_T_CN; + pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_T_CN; + pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_T_CN; + eeprom_menu.title = EEPROM_SETTINGS_TITLE_T_CN; + eeprom_menu.store = EEPROM_SETTINGS_STORE_T_CN; + eeprom_menu.read = EEPROM_SETTINGS_READ_T_CN; + eeprom_menu.revert = EEPROM_SETTINGS_REVERT_T_CN; + eeprom_menu.storeTips = EEPROM_STORE_TIPS_T_CN; + eeprom_menu.readTips = EEPROM_READ_TIPS_T_CN; + eeprom_menu.revertTips = EEPROM_REVERT_TIPS_T_CN; + break; + case LANG_ENGLISH: + common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_EN; + common_menu.text_back = BACK_TEXT_EN; + common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_EN; + common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_EN; + common_menu.print_special_title = PRINTING_OTHER_LANGUGE; + common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE; + common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE; + // + main_menu.title = TITLE_READYPRINT_EN; + main_menu.preheat = PREHEAT_TEXT_EN; + main_menu.move = MOVE_TEXT_EN; + main_menu.home = HOME_TEXT_EN; + main_menu.print = PRINT_TEXT_EN; + main_menu.extrude = EXTRUDE_TEXT_EN; + main_menu.leveling = LEVELING_TEXT_EN; + main_menu.autoleveling = AUTO_LEVELING_TEXT_EN; + main_menu.fan = FAN_TEXT_EN; + main_menu.set = SET_TEXT_EN; + main_menu.more = MORE_TEXT_EN; + main_menu.tool = TOOL_TEXT_EN; + // TOOL + tool_menu.title = TOOL_TEXT_EN; + tool_menu.preheat = TOOL_PREHEAT_EN; + tool_menu.extrude = TOOL_EXTRUDE_EN; + tool_menu.move = TOOL_MOVE_EN; + tool_menu.home = TOOL_HOME_EN; + tool_menu.leveling = TOOL_LEVELING_EN; + tool_menu.autoleveling = TOOL_AUTO_LEVELING_EN; + tool_menu.filament = TOOL_FILAMENT_EN; + tool_menu.more = TOOL_MORE_EN; + // + preheat_menu.adjust_title = TITLE_ADJUST_EN; + preheat_menu.title = TITLE_PREHEAT_EN; + preheat_menu.add = ADD_TEXT_EN; + preheat_menu.dec = DEC_TEXT_EN; + preheat_menu.ext1 = EXTRUDER_1_TEXT_EN; + preheat_menu.ext2 = EXTRUDER_2_TEXT_EN; + preheat_menu.hotbed = HEATBED_TEXT_EN; + preheat_menu.off = CLOSE_TEXT_EN; + // + move_menu.title = TITLE_MOVE_EN; + // + home_menu.title = TITLE_HOME_EN; + home_menu.stopmove = HOME_STOPMOVE_EN; + // + file_menu.title = TITLE_CHOOSEFILE_EN; + file_menu.page_up = PAGE_UP_TEXT_EN; + file_menu.page_down = PAGE_DOWN_TEXT_EN; + file_menu.file_loading = FILE_LOADING_EN; + file_menu.no_file = NO_FILE_EN; + file_menu.no_file_and_check = NO_FILE_EN; + // + extrude_menu.title = TITLE_EXTRUDE_EN; + extrude_menu.in = EXTRUDER_IN_TEXT_EN; + extrude_menu.out = EXTRUDER_OUT_TEXT_EN; + extrude_menu.ext1 = EXTRUDER_1_TEXT_EN; + extrude_menu.ext2 = EXTRUDER_2_TEXT_EN; + extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_EN; + extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_EN; + extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_EN; + extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_EN; + // + leveling_menu.title = TITLE_LEVELING_EN; + leveling_menu.position1 = LEVELING_POINT1_TEXT_EN; + leveling_menu.position2 = LEVELING_POINT2_TEXT_EN; + leveling_menu.position3 = LEVELING_POINT3_TEXT_EN; + leveling_menu.position4 = LEVELING_POINT4_TEXT_EN; + leveling_menu.position5 = LEVELING_POINT5_TEXT_EN; + // + set_menu.title = TITLE_SET_EN; + set_menu.filesys = FILESYS_TEXT_EN; + set_menu.wifi = WIFI_TEXT_EN; + set_menu.about = ABOUT_TEXT_EN; + set_menu.fan = FAN_TEXT_EN; + set_menu.filament = FILAMENT_TEXT_EN; + set_menu.breakpoint = BREAK_POINT_TEXT_EN; + set_menu.motoroff = MOTOR_OFF_TEXT_EN; + set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_EN; + set_menu.language = LANGUAGE_TEXT_EN; + set_menu.shutdown = SHUTDOWN_TEXT_EN; + set_menu.machine_para = MACHINE_PARA_EN; + set_menu.eepromSet = EEPROM_SETTINGS_EN; + more_menu.title = TITLE_MORE_EN; + #if ENABLED(USER_CMD_1_ENABLE) + more_menu.custom1 = MORE_CUSTOM1_TEXT_EN; + #endif + #if ENABLED(USER_CMD_2_ENABLE) + more_menu.custom2 = MORE_CUSTOM2_TEXT_EN; + #endif + #if ENABLED(USER_CMD_3_ENABLE) + more_menu.custom3 = MORE_CUSTOM3_TEXT_EN; + #endif + #if ENABLED(USER_CMD_4_ENABLE) + more_menu.custom4 = MORE_CUSTOM4_TEXT_EN; + #endif + #if ENABLED(USER_CMD_5_ENABLE) + more_menu.custom5 = MORE_CUSTOM5_TEXT_EN; + #endif + #if ENABLED(USER_CMD_6_ENABLE) + more_menu.custom6 = MORE_CUSTOM6_TEXT_EN; + #endif + #if ENABLED(USER_CMD_7_ENABLE) + more_menu.custom7 = MORE_CUSTOM7_TEXT_EN; + #endif + + // + filesys_menu.title = TITLE_FILESYS_EN; + filesys_menu.sd_sys = SD_CARD_TEXT_EN; + filesys_menu.usb_sys = U_DISK_TEXT_EN; + // WIFI + wifi_menu.title = WIFI_TEXT; + wifi_menu.cloud = CLOUD_TEXT_EN; + wifi_menu.reconnect = WIFI_RECONNECT_TEXT_EN; + + cloud_menu.title = TITLE_CLOUD_TEXT_EN; + cloud_menu.bind = CLOUD_BINDED_EN; + cloud_menu.binded = CLOUD_BINDED_EN; + cloud_menu.unbind = CLOUD_UNBIND_EN; + cloud_menu.unbinding = CLOUD_UNBINDED_EN; + cloud_menu.disconnected = CLOUD_DISCONNECTED_EN; + cloud_menu.unbinded = CLOUD_UNBINDED_EN; + cloud_menu.disable = CLOUD_DISABLE_EN; + // + about_menu.title = TITLE_ABOUT_EN; + about_menu.type = ABOUT_TYPE_TEXT_EN; + about_menu.version = ABOUT_VERSION_TEXT_EN; + about_menu.wifi = ABOUT_WIFI_TEXT_EN; + // + fan_menu.title = TITLE_FAN_EN; + fan_menu.add = FAN_ADD_TEXT_EN; + fan_menu.dec = FAN_DEC_TEXT_EN; + fan_menu.state = FAN_TIPS1_TEXT_EN; + // + filament_menu.title = TITLE_FILAMENT_EN; + filament_menu.in = FILAMENT_IN_TEXT_EN; + filament_menu.out = FILAMENT_OUT_TEXT_EN; + filament_menu.ext1 = FILAMENT_EXT0_TEXT_EN; + filament_menu.ext2 = FILAMENT_EXT1_TEXT_EN; + filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_EN; + filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_EN; + filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_EN; + filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_EN; + filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_EN; + filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_EN; + filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_EN; + filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_EN; + filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_EN; + + // + language_menu.title = TITLE_LANGUAGE_EN; + language_menu.next = PAGE_DOWN_TEXT_EN; + language_menu.up = PAGE_UP_TEXT_EN; + // + printing_menu.title = TITLE_PRINTING_EN; + printing_menu.option = PRINTING_OPERATION_EN; + printing_menu.stop = PRINTING_STOP_EN; + printing_menu.pause = PRINTING_PAUSE_EN; + printing_menu.resume = PRINTING_RESUME_EN; + + // + operation_menu.title = TITLE_OPERATION_EN; + operation_menu.pause = PRINTING_PAUSE_EN; + operation_menu.stop = PRINTING_STOP_EN; + operation_menu.temp = PRINTING_TEMP_EN; + operation_menu.fan = FAN_TEXT_EN; + operation_menu.extr = PRINTING_EXTRUDER_EN; + operation_menu.speed = PRINTING_CHANGESPEED_EN; + operation_menu.filament = FILAMENT_TEXT_EN; + operation_menu.more = PRINTING_MORE_EN; + operation_menu.move = PRINTING_MOVE_EN; + operation_menu.auto_off = AUTO_SHUTDOWN_EN; + operation_menu.manual_off = MANUAL_SHUTDOWN_EN; + // + pause_menu.title = TITLE_PAUSE_EN; + pause_menu.resume = PRINTING_RESUME_EN; + pause_menu.stop = PRINTING_STOP_EN; + pause_menu.extrude = PRINTING_EXTRUDER_EN; + pause_menu.move = PRINTING_MOVE_EN; + pause_menu.filament = FILAMENT_TEXT_EN; + pause_menu.more = PRINTING_MORE_EN; + + // + speed_menu.title = TITLE_CHANGESPEED_EN; + speed_menu.add = ADD_TEXT_EN; + speed_menu.dec = DEC_TEXT_EN; + speed_menu.move = MOVE_SPEED_EN; + speed_menu.extrude = EXTRUDER_SPEED_EN; + speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_EN; + speed_menu.move_speed = MOVE_SPEED_STATE_EN; + // + printing_more_menu.title = TITLE_MORE_EN; + printing_more_menu.fan = FAN_TEXT_EN; + printing_more_menu.auto_close = AUTO_SHUTDOWN_EN; + printing_more_menu.manual = MANUAL_SHUTDOWN_EN; + printing_more_menu.speed = PRINTING_CHANGESPEED_EN; + printing_more_menu.temp = PRINTING_TEMP_EN; + + print_file_dialog_menu.confirm = DIALOG_CONFIRM_EN; + print_file_dialog_menu.cancel = DIALOG_CANCLE_EN; + print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_EN; + print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_EN; + print_file_dialog_menu.retry = DIALOG_RETRY_EN; + print_file_dialog_menu.stop = DIALOG_STOP_EN; + print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_EN; + print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_EN; + print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_EN; + print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_EN; + print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_EN; + print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_EN; + print_file_dialog_menu.reprint = DIALOG_REPRINT_EN; + print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_EN; + print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_EN; + + pause_msg_menu.pausing = MESSAGE_PAUSING_EN; + pause_msg_menu.changing = MESSAGE_CHANGING_EN; + pause_msg_menu.unload = MESSAGE_UNLOAD_EN; + pause_msg_menu.waiting = MESSAGE_WAITING_EN; + pause_msg_menu.insert = MESSAGE_INSERT_EN; + pause_msg_menu.load = MESSAGE_LOAD_EN; + pause_msg_menu.purge = MESSAGE_PURGE_EN; + pause_msg_menu.resume = MESSAGE_RESUME_EN; + pause_msg_menu.heat = MESSAGE_HEAT_EN; + pause_msg_menu.heating = MESSAGE_HEATING_EN; + pause_msg_menu.option = MESSAGE_OPTION_EN; + pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_EN; + pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_EN; + eeprom_menu.title = EEPROM_SETTINGS_TITLE_EN; + eeprom_menu.store = EEPROM_SETTINGS_STORE_EN; + eeprom_menu.read = EEPROM_SETTINGS_READ_EN; + eeprom_menu.revert = EEPROM_SETTINGS_REVERT_EN; + eeprom_menu.storeTips = EEPROM_STORE_TIPS_EN; + eeprom_menu.readTips = EEPROM_READ_TIPS_EN; + eeprom_menu.revertTips = EEPROM_REVERT_TIPS_EN; + break; + case LANG_RUSSIAN: + common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_RU; + common_menu.text_back = BACK_TEXT_RU; + common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_RU; + common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_RU; + common_menu.print_special_title = PRINTING_OTHER_LANGUGE; + common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE; + common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE; + // + main_menu.title = TITLE_READYPRINT_RU; + main_menu.preheat = PREHEAT_TEXT_RU; + main_menu.move = MOVE_TEXT_RU; + main_menu.home = HOME_TEXT_RU; + main_menu.print = PRINT_TEXT_RU; + main_menu.extrude = EXTRUDE_TEXT_RU; + main_menu.leveling = LEVELING_TEXT_RU; + main_menu.autoleveling = AUTO_LEVELING_TEXT_RU; + main_menu.fan = FAN_TEXT_RU; + main_menu.set = SET_TEXT_RU; + main_menu.more = MORE_TEXT_RU; + main_menu.tool = TOOL_TEXT_RU; + // TOOL + tool_menu.title = TOOL_TEXT_RU; + tool_menu.preheat = TOOL_PREHEAT_RU; + tool_menu.extrude = TOOL_EXTRUDE_RU; + tool_menu.move = TOOL_MOVE_RU; + tool_menu.home = TOOL_HOME_RU; + tool_menu.leveling = TOOL_LEVELING_RU; + tool_menu.autoleveling = TOOL_AUTO_LEVELING_RU; + tool_menu.filament = TOOL_FILAMENT_RU; + tool_menu.more = TOOL_MORE_RU; + // + preheat_menu.adjust_title = TITLE_ADJUST_RU; + preheat_menu.title = TITLE_PREHEAT_RU; + preheat_menu.add = ADD_TEXT_RU; + preheat_menu.dec = DEC_TEXT_RU; + preheat_menu.ext1 = EXTRUDER_1_TEXT_RU; + preheat_menu.ext2 = EXTRUDER_2_TEXT_RU; + preheat_menu.hotbed = HEATBED_TEXT_RU; + preheat_menu.off = CLOSE_TEXT_RU; + // + move_menu.title = MOVE_TEXT_RU; + // + home_menu.title = TITLE_HOME_RU; + home_menu.stopmove = HOME_STOPMOVE_RU; + // + file_menu.title = TITLE_CHOOSEFILE_RU; + file_menu.page_up = PAGE_UP_TEXT_RU; + file_menu.page_down = PAGE_DOWN_TEXT_RU; + file_menu.file_loading = FILE_LOADING_RU; + file_menu.no_file = NO_FILE_RU; + file_menu.no_file_and_check = NO_FILE_RU; + // + extrude_menu.title = TITLE_EXTRUDE_RU; + extrude_menu.in = EXTRUDER_IN_TEXT_RU; + extrude_menu.out = EXTRUDER_OUT_TEXT_RU; + extrude_menu.ext1 = EXTRUDER_1_TEXT_RU; + extrude_menu.ext2 = EXTRUDER_2_TEXT_RU; + extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_RU; + extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_RU; + extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_RU; + extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_RU; + // + leveling_menu.title = TITLE_LEVELING_RU; + leveling_menu.position1 = LEVELING_POINT1_TEXT_RU; + leveling_menu.position2 = LEVELING_POINT2_TEXT_RU; + leveling_menu.position3 = LEVELING_POINT3_TEXT_RU; + leveling_menu.position4 = LEVELING_POINT4_TEXT_RU; + leveling_menu.position5 = LEVELING_POINT5_TEXT_RU; + // + set_menu.title = TITLE_SET_RU; + set_menu.filesys = FILESYS_TEXT_RU; + set_menu.wifi = WIFI_TEXT_RU; + set_menu.about = ABOUT_TEXT_RU; + set_menu.fan = FAN_TEXT_RU; + set_menu.filament = FILAMENT_TEXT_RU; + set_menu.breakpoint = BREAK_POINT_TEXT_RU; + set_menu.motoroff = MOTOR_OFF_TEXT_RU; + set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_RU; + set_menu.language = LANGUAGE_TEXT_RU; + set_menu.shutdown = SHUTDOWN_TEXT_RU; + set_menu.machine_para = MACHINE_PARA_RU; + set_menu.eepromSet = EEPROM_SETTINGS_RU; + more_menu.title = TITLE_MORE_RU; + #if ENABLED(USER_CMD_1_ENABLE) + more_menu.custom1 = MORE_CUSTOM1_TEXT_RU; + #endif + #if ENABLED(USER_CMD_2_ENABLE) + more_menu.custom2 = MORE_CUSTOM2_TEXT_RU; + #endif + #if ENABLED(USER_CMD_3_ENABLE) + more_menu.custom3 = MORE_CUSTOM3_TEXT_RU; + #endif + #if ENABLED(USER_CMD_4_ENABLE) + more_menu.custom4 = MORE_CUSTOM4_TEXT_RU; + #endif + #if ENABLED(USER_CMD_5_ENABLE) + more_menu.custom5 = MORE_CUSTOM5_TEXT_RU; + #endif + #if ENABLED(USER_CMD_6_ENABLE) + more_menu.custom6 = MORE_CUSTOM6_TEXT_RU; + #endif + #if ENABLED(USER_CMD_7_ENABLE) + more_menu.custom7 = MORE_CUSTOM7_TEXT_RU; + #endif + // + filesys_menu.title = TITLE_FILESYS_RU; + filesys_menu.sd_sys = SD_CARD_TEXT_RU; + filesys_menu.usb_sys = U_DISK_TEXT_RU; + // WIFI + wifi_menu.title = WIFI_TEXT; + wifi_menu.cloud = CLOUD_TEXT_RU; + wifi_menu.reconnect = WIFI_RECONNECT_TEXT_RU; + + machine_menu.next = NEXT_RU; + machine_menu.previous = PREVIOUS_RU; + machine_menu.enable = ENABLE_RU; + machine_menu.disable = DISABLE_RU; + machine_menu.key_confirm = KEY_CONFIRM_RU; + + MachinePara_menu.MachineSetting = MACHINE_TYPE_CNOFIG_RU; + MachinePara_menu.title = MACHINE_PARA_TITLE_RU; + machine_menu.MachineConfigTitle = MACHINE_CONFIG_TITLE_RU; + MachinePara_menu.MotorSetting = MOTOR_CONFIG_RU; + MachinePara_menu.leveling = MACHINE_LEVELING_CONFIG_RU; + MachinePara_menu.AdvanceSetting = ADVANCE_CONFIG_RU; + machine_menu.MotorConfTitle = MOTOR_CONF_TITLE_RU; + machine_menu.MaxFeedRateConf = MAXFEEDRATE_CONF_RU; + machine_menu.AccelerationConf = ACCELERATION_CONF_RU; + machine_menu.JerkConf = JERKCONF_RU; + machine_menu.StepsConf = STEPSCONF_RU; + machine_menu.TMCcurrentConf = TMC_CURRENT_RU; + machine_menu.TMCStepModeConf = TMC_STEP_MODE_RU; + machine_menu.PausePosition = PAUSE_POSITION_RU; + machine_menu.FilamentConf = MACHINE_FILAMENT_CONFIG_RU; + machine_menu.EncoderSettings = ENCODER_SETTINGS_RU; + machine_menu.AdvancedConfTitle = ADVANCED_CONF_TITLE_RU; + + machine_menu.LevelingParaConfTitle = LEVELING_CONF_TITLE_RU; + machine_menu.LevelingParaConf = LEVELING_PARA_CONF_RU; + machine_menu.LevelingManuPosConf = LEVELING_MANUAL_POS_RU; + machine_menu.LevelingAutoCommandConf = LEVELING_AUTO_COMMAND_RU; + machine_menu.LevelingAutoZoffsetConf = LEVELING_AUTO_ZOFFSET_RU; + + machine_menu.AccelerationConfTitle = ACCELERATION_CONF_TITLE_RU; + machine_menu.PrintAcceleration = PRINT_ACCELERATION_RU; + machine_menu.RetractAcceleration = RETRACT_ACCELERATION_RU; + machine_menu.TravelAcceleration = TRAVEL_ACCELERATION_RU; + machine_menu.X_Acceleration = X_ACCELERATION_RU; + machine_menu.Y_Acceleration = Y_ACCELERATION_RU; + machine_menu.Z_Acceleration = Z_ACCELERATION_RU; + machine_menu.E0_Acceleration = E0_ACCELERATION_RU; + machine_menu.E1_Acceleration = E1_ACCELERATION_RU; + + machine_menu.MaxFeedRateConfTitle = MAXFEEDRATE_CONF_TITLE_RU; + machine_menu.XMaxFeedRate = X_MAXFEEDRATE_RU; + machine_menu.YMaxFeedRate = Y_MAXFEEDRATE_RU; + machine_menu.ZMaxFeedRate = Z_MAXFEEDRATE_RU; + machine_menu.E0MaxFeedRate = E0_MAXFEEDRATE_RU; + machine_menu.E1MaxFeedRate = E1_MAXFEEDRATE_RU; + + machine_menu.JerkConfTitle = JERK_CONF_TITLE_RU; + machine_menu.X_Jerk = X_JERK_RU; + machine_menu.Y_Jerk = Y_JERK_RU; + machine_menu.Z_Jerk = Z_JERK_RU; + machine_menu.E_Jerk = E_JERK_RU; + + machine_menu.StepsConfTitle = STEPS_CONF_TITLE_RU; + machine_menu.X_Steps = X_STEPS_RU; + machine_menu.Y_Steps = Y_STEPS_RU; + machine_menu.Z_Steps = Z_STEPS_RU; + machine_menu.E0_Steps = E0_STEPS_RU; + machine_menu.E1_Steps = E1_STEPS_RU; + + machine_menu.TmcCurrentConfTitle = TMC_CURRENT_CONF_TITLE_RU; + machine_menu.X_Current = X_TMC_CURRENT_RU; + machine_menu.Y_Current = Y_TMC_CURRENT_RU; + machine_menu.Z_Current = Z_TMC_CURRENT_RU; + machine_menu.E0_Current = E0_TMC_CURRENT_RU; + machine_menu.E1_Current = E1_TMC_CURRENT_RU; + + machine_menu.TmcStepModeConfTitle = TMC_MODE_CONF_TITLE_RU; + machine_menu.X_StepMode = X_TMC_MODE_RU; + machine_menu.Y_StepMode = Y_TMC_MODE_RU; + machine_menu.Z_StepMode = Z_TMC_MODE_RU; + machine_menu.E0_StepMode = E0_TMC_MODE_RU; + machine_menu.E1_StepMode = E1_TMC_MODE_RU; + + machine_menu.PausePosText = PAUSE_POSITION_RU; + machine_menu.xPos = PAUSE_POSITION_X_RU; + machine_menu.yPos = PAUSE_POSITION_Y_RU; + machine_menu.zPos = PAUSE_POSITION_Z_RU; + + machine_menu.OffsetConfTitle = OFFSET_TITLE_RU; + machine_menu.Xoffset = OFFSET_X_RU; + machine_menu.Yoffset = OFFSET_Y_RU; + machine_menu.Zoffset = OFFSET_Z_RU; + + machine_menu.LevelingTouchmiConf = LEVELING_TOUCHMI_RU; + machine_menu.TouchmiInit = TM_INIT_RU; + machine_menu.TouchmiOffsetpos = TM_ZOFFSETPOS_RU; + machine_menu.TouchmiOffsetneg = TM_ZOFFSETNEG_RU; + machine_menu.TouchmiSave = TM_SAVE_RU; + machine_menu.TouchmiTest = TM_TEST_RU; + + machine_menu.BLTouchLevelingConfTitle = BLTOUCH_LEVELING_TITTLE_RU; + machine_menu.BLTouchLevelingConf = BLTOUCH_LEVELING_RU; + machine_menu.BLTouchInit = BLTOUCH_INIT_RU; + machine_menu.BLTouchOffsetpos = BLTOUCH_ZOFFSETPOS_RU; + machine_menu.BLTouchOffsetneg = BLTOUCH_ZOFFSETNEG_RU; + machine_menu.BLTouchSave = BLTOUCH_SAVE_RU; + machine_menu.BLTouchTest = BLTOUCH_TEST_RU; + + machine_menu.FilamentConfTitle = FILAMENT_CONF_TITLE_RU; + machine_menu.InLength = FILAMENT_IN_LENGTH_RU; + machine_menu.InSpeed = FILAMENT_IN_SPEED_RU; + machine_menu.FilamentTemperature = FILAMENT_TEMPERATURE_RU; + machine_menu.OutLength = FILAMENT_OUT_LENGTH_RU; + machine_menu.OutSpeed = FILAMENT_OUT_SPEED_RU; + + machine_menu.EncoderConfTitle = ENCODER_CONF_TITLE_RU; + machine_menu.EncoderConfText = ENCODER_CONF_TEXT_RU; + + + cloud_menu.title = TITLE_CLOUD_TEXT_RU; + cloud_menu.bind = CLOUD_BINDED_RU; + cloud_menu.binded = CLOUD_BINDED_RU; + cloud_menu.unbind = CLOUD_UNBIND_RU; + cloud_menu.unbinding = CLOUD_UNBINDED_RU; + cloud_menu.disconnected = CLOUD_DISCONNECTED_RU; + cloud_menu.unbinded = CLOUD_UNBINDED_RU; + cloud_menu.disable = CLOUD_DISABLE_RU; + // + about_menu.title = ABOUT_TEXT_RU; + about_menu.type = ABOUT_TYPE_TEXT_RU; + about_menu.version = ABOUT_VERSION_TEXT_RU; + about_menu.wifi = ABOUT_WIFI_TEXT_RU; + // + fan_menu.title = FAN_TEXT_RU; + fan_menu.add = FAN_ADD_TEXT_RU; + fan_menu.dec = FAN_DEC_TEXT_RU; + fan_menu.state = FAN_TIPS1_TEXT_RU; + // + filament_menu.title = TITLE_FILAMENT_RU; + filament_menu.in = FILAMENT_IN_TEXT_RU; + filament_menu.out = FILAMENT_OUT_TEXT_RU; + filament_menu.ext1 = FILAMENT_EXT0_TEXT_RU; + filament_menu.ext2 = FILAMENT_EXT1_TEXT_RU; + filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_RU; + filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_RU; + filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_RU; + filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_RU; + filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_RU; + filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_RU; + filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_RU; + filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_RU; + filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_RU; + + // + language_menu.title = LANGUAGE_TEXT_RU; + language_menu.next = PAGE_DOWN_TEXT_RU; + language_menu.up = PAGE_UP_TEXT_RU; + // + printing_menu.title = TITLE_PRINTING_RU; + printing_menu.option = PRINTING_OPERATION_RU; + printing_menu.stop = PRINTING_STOP_RU; + printing_menu.pause = PRINTING_PAUSE_RU; + printing_menu.resume = PRINTING_RESUME_RU; + + // + operation_menu.title = TITLE_OPERATION_RU; + operation_menu.pause = PRINTING_PAUSE_RU; + operation_menu.stop = PRINTING_STOP_RU; + operation_menu.temp = PRINTING_TEMP_RU; + operation_menu.fan = FAN_TEXT_RU; + operation_menu.extr = PRINTING_EXTRUDER_RU; + operation_menu.speed = PRINTING_CHANGESPEED_RU; + operation_menu.filament = FILAMENT_TEXT_RU; + operation_menu.more = PRINTING_MORE_RU; + operation_menu.move = PRINTING_MOVE_RU; + operation_menu.auto_off = AUTO_SHUTDOWN_RU; + operation_menu.manual_off = MANUAL_SHUTDOWN_RU; + // + pause_menu.title = TITLE_PAUSE_RU; + pause_menu.resume = PRINTING_RESUME_RU; + pause_menu.stop = PRINTING_STOP_RU; + pause_menu.extrude = PRINTING_EXTRUDER_RU; + pause_menu.move = PRINTING_MOVE_RU; + pause_menu.filament = FILAMENT_TEXT_RU; + pause_menu.more = PRINTING_MORE_RU; + + // + speed_menu.title = PRINTING_CHANGESPEED_RU; + speed_menu.add = ADD_TEXT_RU; + speed_menu.dec = DEC_TEXT_RU; + speed_menu.move = MOVE_SPEED_RU; + speed_menu.extrude = EXTRUDER_SPEED_RU; + speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_RU; + speed_menu.move_speed = MOVE_SPEED_STATE_RU; + // + printing_more_menu.title = TITLE_MORE_RU; + printing_more_menu.fan = FAN_TEXT_RU; + printing_more_menu.auto_close = AUTO_SHUTDOWN_RU; + printing_more_menu.manual = MANUAL_SHUTDOWN_RU; + printing_more_menu.speed = PRINTING_CHANGESPEED_RU; + printing_more_menu.temp = PRINTING_TEMP_RU; + print_file_dialog_menu.confirm = DIALOG_CONFIRM_RU; + print_file_dialog_menu.cancel = DIALOG_CANCLE_RU; + print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_RU; + print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_RU; + print_file_dialog_menu.retry = DIALOG_RETRY_RU; + print_file_dialog_menu.stop = DIALOG_STOP_RU; + print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_RU; + print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_RU; + print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_RU; + print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_RU; + print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_RU; + print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_RU; + print_file_dialog_menu.reprint = DIALOG_REPRINT_RU; + print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_RU; + print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_RU; + + pause_msg_menu.pausing = MESSAGE_PAUSING_RU; + pause_msg_menu.changing = MESSAGE_CHANGING_RU; + pause_msg_menu.unload = MESSAGE_UNLOAD_RU; + pause_msg_menu.waiting = MESSAGE_WAITING_RU; + pause_msg_menu.insert = MESSAGE_INSERT_RU; + pause_msg_menu.load = MESSAGE_LOAD_RU; + pause_msg_menu.purge = MESSAGE_PURGE_RU; + pause_msg_menu.resume = MESSAGE_RESUME_RU; + pause_msg_menu.heat = MESSAGE_HEAT_RU; + pause_msg_menu.heating = MESSAGE_HEATING_RU; + pause_msg_menu.option = MESSAGE_OPTION_RU; + pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_RU; + pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_RU; + eeprom_menu.title = EEPROM_SETTINGS_TITLE_RU; + eeprom_menu.store = EEPROM_SETTINGS_STORE_RU; + eeprom_menu.read = EEPROM_SETTINGS_READ_RU; + eeprom_menu.revert = EEPROM_SETTINGS_REVERT_RU; + eeprom_menu.storeTips = EEPROM_STORE_TIPS_RU; + eeprom_menu.readTips = EEPROM_READ_TIPS_RU; + eeprom_menu.revertTips = EEPROM_REVERT_TIPS_RU; + break; + case LANG_SPANISH: + common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_SP; + common_menu.text_back = BACK_TEXT_SP; + common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_SP; + common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_SP; + common_menu.print_special_title = PRINTING_SP; + common_menu.pause_special_title = PRINTING_PAUSAR_SP; + common_menu.operate_special_title = PRINTING_AJUSTES_SP; + // + main_menu.title = TITLE_READYPRINT_SP; + main_menu.preheat = PREHEAT_TEXT_SP; + main_menu.move = MOVE_TEXT_SP; + main_menu.home = HOME_TEXT_SP; + main_menu.print = PRINT_TEXT_SP; + main_menu.extrude = EXTRUDE_TEXT_SP; + main_menu.leveling = LEVELING_TEXT_SP; + main_menu.autoleveling = AUTO_LEVELING_TEXT_SP; + main_menu.fan = FAN_TEXT_SP; + main_menu.set = SET_TEXT_SP; + main_menu.more = MORE_TEXT_SP; + main_menu.tool = TOOL_TEXT_SP; + // TOOL + tool_menu.title = TOOL_TEXT_SP; + tool_menu.preheat = TOOL_PREHEAT_SP; + tool_menu.extrude = TOOL_EXTRUDE_SP; + tool_menu.move = TOOL_MOVE_SP; + tool_menu.home = TOOL_HOME_SP; + tool_menu.leveling = TOOL_LEVELING_SP; + tool_menu.autoleveling = TOOL_AUTO_LEVELING_SP; + tool_menu.filament = TOOL_FILAMENT_SP; + tool_menu.more = TOOL_MORE_SP; + // + preheat_menu.adjust_title = TITLE_ADJUST_SP; + preheat_menu.title = TITLE_PREHEAT_SP; + preheat_menu.add = ADD_TEXT_SP; + preheat_menu.dec = DEC_TEXT_SP; + preheat_menu.ext1 = EXTRUDER_1_TEXT_SP; + preheat_menu.ext2 = EXTRUDER_2_TEXT_SP; + preheat_menu.hotbed = HEATBED_TEXT_SP; + preheat_menu.off = CLOSE_TEXT_SP; + // + move_menu.title = MOVE_TEXT_SP; + // + home_menu.title = TITLE_HOME_SP; + home_menu.home_x = HOME_X_TEXT_SP; + home_menu.home_y = HOME_Y_TEXT_SP; + home_menu.home_z = HOME_Z_TEXT_SP; + home_menu.home_all = HOME_ALL_TEXT_SP; + home_menu.stopmove = HOME_STOPMOVE_SP; + // + file_menu.title = TITLE_CHOOSEFILE_SP; + file_menu.page_up = PAGE_UP_TEXT_SP; + file_menu.page_down = PAGE_DOWN_TEXT_SP; + file_menu.file_loading = FILE_LOADING_SP; + file_menu.no_file = NO_FILE_SP; + file_menu.no_file_and_check = NO_FILE_SP; + // + extrude_menu.title = TITLE_EXTRUDE_SP; + extrude_menu.in = EXTRUDER_IN_TEXT_SP; + extrude_menu.out = EXTRUDER_OUT_TEXT_SP; + extrude_menu.ext1 = EXTRUDER_1_TEXT_SP; + extrude_menu.ext2 = EXTRUDER_2_TEXT_SP; + extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_SP; + extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_SP; + extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_SP; + extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_SP; + // + leveling_menu.title = TITLE_LEVELING_SP; + leveling_menu.position1 = LEVELING_POINT1_TEXT_SP; + leveling_menu.position2 = LEVELING_POINT2_TEXT_SP; + leveling_menu.position3 = LEVELING_POINT3_TEXT_SP; + leveling_menu.position4 = LEVELING_POINT4_TEXT_SP; + leveling_menu.position5 = LEVELING_POINT5_TEXT_SP; + // + set_menu.title = TITLE_SET_SP; + set_menu.filesys = FILESYS_TEXT_SP; + set_menu.wifi = WIFI_TEXT_SP; + set_menu.about = ABOUT_TEXT_SP; + set_menu.fan = FAN_TEXT_SP; + set_menu.filament = FILAMENT_TEXT_SP; + set_menu.breakpoint = BREAK_POINT_TEXT_SP; + set_menu.motoroff = MOTOR_OFF_TEXT_SP; + set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_SP; + set_menu.language = LANGUAGE_TEXT_SP; + set_menu.shutdown = SHUTDOWN_TEXT_SP; + set_menu.machine_para = MACHINE_PARA_SP; + set_menu.eepromSet = EEPROM_SETTINGS_SP; + more_menu.title = TITLE_MORE_SP; + #if ENABLED(USER_CMD_1_ENABLE) + more_menu.custom1 = MORE_CUSTOM1_TEXT_SP; + #endif + #if ENABLED(USER_CMD_2_ENABLE) + more_menu.custom2 = MORE_CUSTOM2_TEXT_SP; + #endif + #if ENABLED(USER_CMD_3_ENABLE) + more_menu.custom3 = MORE_CUSTOM3_TEXT_SP; + #endif + #if ENABLED(USER_CMD_4_ENABLE) + more_menu.custom4 = MORE_CUSTOM4_TEXT_SP; + #endif + #if ENABLED(USER_CMD_5_ENABLE) + more_menu.custom5 = MORE_CUSTOM5_TEXT_SP; + #endif + #if ENABLED(USER_CMD_6_ENABLE) + more_menu.custom6 = MORE_CUSTOM6_TEXT_SP; + #endif + #if ENABLED(USER_CMD_7_ENABLE) + more_menu.custom7 = MORE_CUSTOM7_TEXT_SP; + #endif + // + filesys_menu.title = TITLE_FILESYS_SP; + filesys_menu.sd_sys = SD_CARD_TEXT_SP; + filesys_menu.usb_sys = U_DISK_TEXT_SP; + + // WIFI + wifi_menu.title = WIFI_TEXT; + wifi_menu.cloud = CLOUD_TEXT_SP; + wifi_menu.reconnect = WIFI_RECONNECT_TEXT_SP; + + cloud_menu.title = TITLE_CLOUD_TEXT_SP; + cloud_menu.bind = CLOUD_BINDED_SP; + cloud_menu.binded = CLOUD_BINDED_SP; + cloud_menu.unbind = CLOUD_UNBIND_SP; + cloud_menu.unbinding = CLOUD_UNBINDED_SP; + cloud_menu.disconnected = CLOUD_DISCONNECTED_SP; + cloud_menu.unbinded = CLOUD_UNBINDED_SP; + cloud_menu.disable = CLOUD_DISABLE_SP; + // + about_menu.title = ABOUT_TEXT_SP; + about_menu.type = ABOUT_TYPE_TEXT_SP; + about_menu.version = ABOUT_VERSION_TEXT_SP; + about_menu.wifi = ABOUT_WIFI_TEXT_SP; + // + fan_menu.title = FAN_TEXT_SP; + fan_menu.add = FAN_ADD_TEXT_SP; + fan_menu.dec = FAN_DEC_TEXT_SP; + fan_menu.state = FAN_TIPS1_TEXT_SP; + // + filament_menu.title = TITLE_FILAMENT_SP; + filament_menu.in = FILAMENT_IN_TEXT_SP; + filament_menu.out = FILAMENT_OUT_TEXT_SP; + filament_menu.ext1 = FILAMENT_EXT0_TEXT_SP; + filament_menu.ext2 = FILAMENT_EXT1_TEXT_SP; + filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_SP; + filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_SP; + filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_SP; + filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_SP; + filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_SP; + filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_SP; + filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_SP; + filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_SP; + filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_SP; + + // + language_menu.title = LANGUAGE_TEXT_SP; + language_menu.next = PAGE_DOWN_TEXT_SP; + language_menu.up = PAGE_UP_TEXT_SP; + // + printing_menu.title = TITLE_PRINTING_SP; + printing_menu.option = PRINTING_OPERATION_SP; + printing_menu.stop = PRINTING_STOP_SP; + printing_menu.pause = PRINTING_PAUSE_SP; + printing_menu.resume = PRINTING_RESUME_SP; + + // + operation_menu.title = TITLE_OPERATION_SP; + operation_menu.pause = PRINTING_PAUSE_SP; + operation_menu.stop = PRINTING_STOP_SP; + operation_menu.temp = PRINTING_TEMP_SP; + operation_menu.fan = FAN_TEXT_SP; + operation_menu.extr = PRINTING_EXTRUDER_SP; + operation_menu.speed = PRINTING_CHANGESPEED_SP; + operation_menu.filament = FILAMENT_TEXT_SP; + operation_menu.more = PRINTING_MORE_SP; + operation_menu.move = PRINTING_MOVE_SP; + operation_menu.auto_off = AUTO_SHUTDOWN_SP; + operation_menu.manual_off = MANUAL_SHUTDOWN_SP; + // + pause_menu.title = TITLE_PAUSE_RU; + pause_menu.resume = PRINTING_RESUME_SP; + pause_menu.stop = PRINTING_STOP_SP; + pause_menu.extrude = PRINTING_EXTRUDER_SP; + pause_menu.move = PRINTING_MOVE_SP; + pause_menu.filament = FILAMENT_TEXT_SP; + pause_menu.more = PRINTING_MORE_SP; + + // + speed_menu.title = PRINTING_CHANGESPEED_SP; + speed_menu.add = ADD_TEXT_SP; + speed_menu.dec = DEC_TEXT_SP; + speed_menu.move = MOVE_SPEED_SP; + speed_menu.extrude = EXTRUDER_SPEED_SP; + speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_SP; + speed_menu.move_speed = MOVE_SPEED_STATE_SP; + // + printing_more_menu.title = TITLE_MORE_SP; + printing_more_menu.fan = FAN_TEXT_SP; + printing_more_menu.auto_close = AUTO_SHUTDOWN_SP; + printing_more_menu.manual = MANUAL_SHUTDOWN_SP; + printing_more_menu.speed = PRINTING_CHANGESPEED_SP; + printing_more_menu.temp = PRINTING_TEMP_SP; + + print_file_dialog_menu.confirm = DIALOG_CONFIRM_SP; + print_file_dialog_menu.cancel = DIALOG_CANCLE_SP; + print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_SP; + print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_SP; + print_file_dialog_menu.retry = DIALOG_RETRY_SP; + print_file_dialog_menu.stop = DIALOG_STOP_SP; + print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_SP; + print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_SP; + print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_SP; + print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_SP; + print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_SP; + print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_SP; + print_file_dialog_menu.reprint = DIALOG_REPRINT_SP; + print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_SP; + print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_SP; + + pause_msg_menu.pausing = MESSAGE_PAUSING_SP; + pause_msg_menu.changing = MESSAGE_CHANGING_SP; + pause_msg_menu.unload = MESSAGE_UNLOAD_SP; + pause_msg_menu.waiting = MESSAGE_WAITING_SP; + pause_msg_menu.insert = MESSAGE_INSERT_SP; + pause_msg_menu.load = MESSAGE_LOAD_SP; + pause_msg_menu.purge = MESSAGE_PURGE_SP; + pause_msg_menu.resume = MESSAGE_RESUME_SP; + pause_msg_menu.heat = MESSAGE_HEAT_SP; + pause_msg_menu.heating = MESSAGE_HEATING_SP; + pause_msg_menu.option = MESSAGE_OPTION_SP; + pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_SP; + pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_SP; + eeprom_menu.title = EEPROM_SETTINGS_TITLE_SP; + eeprom_menu.store = EEPROM_SETTINGS_STORE_SP; + eeprom_menu.read = EEPROM_SETTINGS_READ_SP; + eeprom_menu.revert = EEPROM_SETTINGS_REVERT_SP; + eeprom_menu.storeTips = EEPROM_STORE_TIPS_SP; + eeprom_menu.readTips = EEPROM_READ_TIPS_SP; + eeprom_menu.revertTips = EEPROM_REVERT_TIPS_SP; + break; + + #endif // if 1 + + case LANG_FRENCH: + common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_FR; + common_menu.text_back = BACK_TEXT_FR; + common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_FR; + common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_FR; + common_menu.print_special_title = PRINTING_OTHER_LANGUGE; + common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE; + common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE; + + // + main_menu.title = TITLE_READYPRINT_FR; + main_menu.preheat = PREHEAT_TEXT_FR; + main_menu.move = MOVE_TEXT_FR; + main_menu.home = HOME_TEXT_FR; + main_menu.print = PRINT_TEXT_FR; + main_menu.extrude = EXTRUDE_TEXT_FR; + main_menu.leveling = LEVELING_TEXT_FR; + main_menu.autoleveling = AUTO_LEVELING_TEXT_FR; + main_menu.fan = FAN_TEXT_FR; + main_menu.set = SET_TEXT_FR; + main_menu.more = MORE_TEXT_FR; + main_menu.tool = TOOL_TEXT_FR; + // TOOL + tool_menu.title = TOOL_TEXT_FR; + tool_menu.preheat = TOOL_PREHEAT_FR; + tool_menu.extrude = TOOL_EXTRUDE_FR; + tool_menu.move = TOOL_MOVE_FR; + tool_menu.home = TOOL_HOME_FR; + tool_menu.leveling = TOOL_LEVELING_FR; + tool_menu.autoleveling = TOOL_AUTO_LEVELING_FR; + tool_menu.filament = TOOL_FILAMENT_FR; + tool_menu.more = TOOL_MORE_FR; + // + preheat_menu.adjust_title = TITLE_ADJUST_FR; + preheat_menu.title = TITLE_PREHEAT_FR; + preheat_menu.add = ADD_TEXT_FR; + preheat_menu.dec = DEC_TEXT_FR; + preheat_menu.ext1 = EXTRUDER_1_TEXT_FR; + preheat_menu.ext2 = EXTRUDER_2_TEXT_FR; + preheat_menu.hotbed = HEATBED_TEXT_FR; + preheat_menu.off = CLOSE_TEXT_FR; + // + move_menu.title = MOVE_TEXT_FR; + // + home_menu.title = TITLE_HOME_FR; + home_menu.stopmove = HOME_STOPMOVE_FR; + // + file_menu.title = TITLE_CHOOSEFILE_FR; + file_menu.page_up = PAGE_UP_TEXT_FR; + file_menu.page_down = PAGE_DOWN_TEXT_FR; + // + extrude_menu.title = TITLE_EXTRUDE_FR; + extrude_menu.in = EXTRUDER_IN_TEXT_FR; + extrude_menu.out = EXTRUDER_OUT_TEXT_FR; + extrude_menu.ext1 = EXTRUDER_1_TEXT_FR; + extrude_menu.ext2 = EXTRUDER_2_TEXT_FR; + extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_FR; + extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_FR; + extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_FR; + extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_FR; + // + leveling_menu.title = TITLE_LEVELING_FR; + leveling_menu.position1 = LEVELING_POINT1_TEXT_FR; + leveling_menu.position2 = LEVELING_POINT2_TEXT_FR; + leveling_menu.position3 = LEVELING_POINT3_TEXT_FR; + leveling_menu.position4 = LEVELING_POINT4_TEXT_FR; + leveling_menu.position5 = LEVELING_POINT5_TEXT_FR; + // + set_menu.title = TITLE_SET_FR; + set_menu.filesys = FILESYS_TEXT_FR; + set_menu.wifi = WIFI_TEXT_FR; + set_menu.about = ABOUT_TEXT_FR; + set_menu.fan = FAN_TEXT_FR; + set_menu.filament = FILAMENT_TEXT_FR; + set_menu.breakpoint = BREAK_POINT_TEXT_FR; + set_menu.motoroff = MOTOR_OFF_TEXT_FR; + set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_FR; + set_menu.language = LANGUAGE_TEXT_FR; + set_menu.shutdown = SHUTDOWN_TEXT_FR; + set_menu.machine_para = MACHINE_PARA_FR; + set_menu.eepromSet = EEPROM_SETTINGS_FR; + more_menu.title = TITLE_MORE_FR; + #if ENABLED(USER_CMD_1_ENABLE) + more_menu.custom1 = MORE_CUSTOM1_TEXT_FR; + #endif + #if ENABLED(USER_CMD_2_ENABLE) + more_menu.custom2 = MORE_CUSTOM2_TEXT_FR; + #endif + #if ENABLED(USER_CMD_3_ENABLE) + more_menu.custom3 = MORE_CUSTOM3_TEXT_FR; + #endif + #if ENABLED(USER_CMD_4_ENABLE) + more_menu.custom4 = MORE_CUSTOM4_TEXT_FR; + #endif + #if ENABLED(USER_CMD_5_ENABLE) + more_menu.custom5 = MORE_CUSTOM5_TEXT_FR; + #endif + #if ENABLED(USER_CMD_6_ENABLE) + more_menu.custom6 = MORE_CUSTOM6_TEXT_FR; + #endif + #if ENABLED(USER_CMD_7_ENABLE) + more_menu.custom7 = MORE_CUSTOM7_TEXT_FR; + #endif + // + filesys_menu.title = TITLE_FILESYS_FR; + filesys_menu.sd_sys = SD_CARD_TEXT_FR; + filesys_menu.usb_sys = U_DISK_TEXT_FR; + file_menu.file_loading = FILE_LOADING_FR; + file_menu.no_file = NO_FILE_FR; + file_menu.no_file_and_check = NO_FILE_FR; + // WIFI + wifi_menu.title = WIFI_NAME_TEXT_FR; + wifi_menu.cloud = CLOUD_TEXT_FR; + wifi_menu.reconnect = WIFI_RECONNECT_TEXT_FR; + + cloud_menu.title = TITLE_CLOUD_TEXT_FR; + cloud_menu.bind = CLOUD_BINDED_FR; + cloud_menu.binded = CLOUD_BINDED_FR; + cloud_menu.unbind = CLOUD_UNBIND_FR; + cloud_menu.unbinding = CLOUD_UNBINDED_FR; + cloud_menu.disconnected = CLOUD_DISCONNECTED_FR; + cloud_menu.unbinded = CLOUD_UNBINDED_FR; + cloud_menu.disable = CLOUD_DISABLE_FR; + // + about_menu.title = ABOUT_TEXT_FR; + about_menu.type = ABOUT_TYPE_TEXT_FR; + about_menu.version = ABOUT_VERSION_TEXT_FR; + about_menu.wifi = ABOUT_WIFI_TEXT_FR; + // + fan_menu.title = FAN_TEXT_FR; + fan_menu.add = FAN_ADD_TEXT_FR; + fan_menu.dec = FAN_DEC_TEXT_FR; + fan_menu.state = FAN_TIPS1_TEXT_FR; + // + filament_menu.title = TITLE_FILAMENT_FR; + filament_menu.in = FILAMENT_IN_TEXT_FR; + filament_menu.out = FILAMENT_OUT_TEXT_FR; + filament_menu.ext1 = FILAMENT_EXT0_TEXT_FR; + filament_menu.ext2 = FILAMENT_EXT1_TEXT_FR; + filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_FR; + filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_FR; + filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_FR; + filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_FR; + filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_FR; + filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_FR; + filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_FR; + filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_FR; + filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_FR; + + // + language_menu.title = LANGUAGE_TEXT_FR; + + // + printing_menu.title = TITLE_PRINTING_FR; + printing_menu.option = PRINTING_OPERATION_FR; + printing_menu.stop = PRINTING_STOP_FR; + printing_menu.pause = PRINTING_PAUSE_FR; + printing_menu.resume = PRINTING_RESUME_FR; + + // + operation_menu.title = TITLE_OPERATION_FR; + operation_menu.pause = PRINTING_PAUSE_FR; + operation_menu.stop = PRINTING_STOP_FR; + operation_menu.temp = PRINTING_TEMP_FR; + operation_menu.fan = FAN_TEXT_FR; + operation_menu.extr = PRINTING_EXTRUDER_FR; + operation_menu.speed = PRINTING_CHANGESPEED_FR; + operation_menu.filament = FILAMENT_TEXT_FR; + operation_menu.more = PRINTING_MORE_FR; + operation_menu.move = PRINTING_MOVE_FR; + operation_menu.auto_off = AUTO_SHUTDOWN_FR; + operation_menu.manual_off = MANUAL_SHUTDOWN_FR; + // + pause_menu.title = TITLE_PAUSE_FR; + pause_menu.resume = PRINTING_RESUME_FR; + pause_menu.stop = PRINTING_STOP_FR; + pause_menu.extrude = PRINTING_EXTRUDER_FR; + pause_menu.move = PRINTING_MOVE_FR; + pause_menu.filament = FILAMENT_TEXT_FR; + pause_menu.more = PRINTING_MORE_FR; + + // + speed_menu.title = PRINTING_CHANGESPEED_FR; + speed_menu.add = ADD_TEXT_FR; + speed_menu.dec = DEC_TEXT_FR; + speed_menu.move = MOVE_SPEED_FR; + speed_menu.extrude = EXTRUDER_SPEED_FR; + speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_FR; + speed_menu.move_speed = MOVE_SPEED_STATE_FR; + // + printing_more_menu.fan = FAN_TEXT_FR; + printing_more_menu.auto_close = AUTO_SHUTDOWN_FR; + printing_more_menu.manual = MANUAL_SHUTDOWN_FR; + printing_more_menu.speed = PRINTING_CHANGESPEED_FR; + printing_more_menu.temp = PRINTING_TEMP_FR; + + print_file_dialog_menu.confirm = DIALOG_CONFIRM_FR; + print_file_dialog_menu.cancel = DIALOG_CANCLE_FR; + print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_FR; + print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_FR; + print_file_dialog_menu.retry = DIALOG_RETRY_FR; + print_file_dialog_menu.stop = DIALOG_STOP_FR; + print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_FR; + print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_FR; + print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_FR; + print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_FR; + print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_FR; + print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_FR; + print_file_dialog_menu.reprint = DIALOG_REPRINT_FR; + print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_FR; + print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_FR; + + pause_msg_menu.pausing = MESSAGE_PAUSING_FR; + pause_msg_menu.changing = MESSAGE_CHANGING_FR; + pause_msg_menu.unload = MESSAGE_UNLOAD_FR; + pause_msg_menu.waiting = MESSAGE_WAITING_FR; + pause_msg_menu.insert = MESSAGE_INSERT_FR; + pause_msg_menu.load = MESSAGE_LOAD_FR; + pause_msg_menu.purge = MESSAGE_PURGE_FR; + pause_msg_menu.resume = MESSAGE_RESUME_FR; + pause_msg_menu.heat = MESSAGE_HEAT_FR; + pause_msg_menu.heating = MESSAGE_HEATING_FR; + pause_msg_menu.option = MESSAGE_OPTION_FR; + pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_FR; + pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_FR; + eeprom_menu.title = EEPROM_SETTINGS_TITLE_FR; + eeprom_menu.store = EEPROM_SETTINGS_STORE_FR; + eeprom_menu.read = EEPROM_SETTINGS_READ_FR; + eeprom_menu.revert = EEPROM_SETTINGS_REVERT_FR; + eeprom_menu.storeTips = EEPROM_STORE_TIPS_FR; + eeprom_menu.readTips = EEPROM_READ_TIPS_FR; + eeprom_menu.revertTips = EEPROM_REVERT_TIPS_FR; + break; + + case LANG_ITALY: + common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_IT; + common_menu.text_back = BACK_TEXT_IT; + common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_IT; + common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_IT; + common_menu.print_special_title = PRINTING_OTHER_LANGUGE; + common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE; + common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE; + + // + main_menu.title = TITLE_READYPRINT_IT; + main_menu.preheat = PREHEAT_TEXT_IT; + main_menu.move = MOVE_TEXT_IT; + main_menu.home = HOME_TEXT_IT; + main_menu.print = PRINT_TEXT_IT; + main_menu.extrude = EXTRUDE_TEXT_IT; + main_menu.leveling = LEVELING_TEXT_IT; + main_menu.autoleveling = AUTO_LEVELING_TEXT_IT; + main_menu.fan = FAN_TEXT_IT; + main_menu.set = SET_TEXT_IT; + main_menu.more = MORE_TEXT_IT; + main_menu.tool = TOOL_TEXT_IT; + // TOOL + tool_menu.title = TOOL_TEXT_IT; + tool_menu.preheat = TOOL_PREHEAT_IT; + tool_menu.extrude = TOOL_EXTRUDE_IT; + tool_menu.move = TOOL_MOVE_IT; + tool_menu.home = TOOL_HOME_IT; + tool_menu.leveling = TOOL_LEVELING_IT; + tool_menu.autoleveling = TOOL_AUTO_LEVELING_IT; + tool_menu.filament = TOOL_FILAMENT_IT; + tool_menu.more = TOOL_MORE_IT; + // + preheat_menu.adjust_title = TITLE_ADJUST_IT; + preheat_menu.title = TITLE_PREHEAT_IT; + preheat_menu.add = ADD_TEXT_IT; + preheat_menu.dec = DEC_TEXT_IT; + preheat_menu.ext1 = EXTRUDER_1_TEXT_IT; + preheat_menu.ext2 = EXTRUDER_2_TEXT_IT; + preheat_menu.hotbed = HEATBED_TEXT_IT; + preheat_menu.off = CLOSE_TEXT_IT; + // + move_menu.title = MOVE_TEXT_IT; + // + home_menu.title = TITLE_HOME_IT; + home_menu.stopmove = HOME_STOPMOVE_IT; + // + file_menu.title = TITLE_CHOOSEFILE_IT; + file_menu.page_up = PAGE_UP_TEXT_IT; + file_menu.page_down = PAGE_DOWN_TEXT_IT; + file_menu.file_loading = FILE_LOADING_IT; + file_menu.no_file = NO_FILE_IT; + file_menu.no_file_and_check = NO_FILE_IT; + // + extrude_menu.title = TITLE_EXTRUDE_IT; + extrude_menu.in = EXTRUDER_IN_TEXT_IT; + extrude_menu.out = EXTRUDER_OUT_TEXT_IT; + extrude_menu.ext1 = EXTRUDER_1_TEXT_IT; + extrude_menu.ext2 = EXTRUDER_2_TEXT_IT; + extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_IT; + extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_IT; + extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_IT; + extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_IT; + // + leveling_menu.title = TITLE_LEVELING_IT; + leveling_menu.position1 = LEVELING_POINT1_TEXT_IT; + leveling_menu.position2 = LEVELING_POINT2_TEXT_IT; + leveling_menu.position3 = LEVELING_POINT3_TEXT_IT; + leveling_menu.position4 = LEVELING_POINT4_TEXT_IT; + leveling_menu.position5 = LEVELING_POINT5_TEXT_IT; + // + set_menu.title = TITLE_SET_IT; + set_menu.filesys = FILESYS_TEXT_IT; + set_menu.wifi = WIFI_TEXT_IT; + set_menu.about = ABOUT_TEXT_IT; + set_menu.fan = FAN_TEXT_IT; + set_menu.filament = FILAMENT_TEXT_IT; + set_menu.breakpoint = BREAK_POINT_TEXT_IT; + set_menu.motoroff = MOTOR_OFF_TEXT_IT; + set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_IT; + set_menu.language = LANGUAGE_TEXT_IT; + set_menu.shutdown = SHUTDOWN_TEXT_IT; + set_menu.machine_para = MACHINE_PARA_IT; + set_menu.eepromSet = EEPROM_SETTINGS_IT; + more_menu.title = TITLE_MORE_IT; + #if ENABLED(USER_CMD_1_ENABLE) + more_menu.custom1 = MORE_CUSTOM1_TEXT_IT; + #endif + #if ENABLED(USER_CMD_2_ENABLE) + more_menu.custom2 = MORE_CUSTOM2_TEXT_IT; + #endif + #if ENABLED(USER_CMD_3_ENABLE) + more_menu.custom3 = MORE_CUSTOM3_TEXT_IT; + #endif + #if ENABLED(USER_CMD_4_ENABLE) + more_menu.custom4 = MORE_CUSTOM4_TEXT_IT; + #endif + #if ENABLED(USER_CMD_5_ENABLE) + more_menu.custom5 = MORE_CUSTOM5_TEXT_IT; + #endif + #if ENABLED(USER_CMD_6_ENABLE) + more_menu.custom6 = MORE_CUSTOM6_TEXT_IT; + #endif + #if ENABLED(USER_CMD_7_ENABLE) + more_menu.custom7 = MORE_CUSTOM7_TEXT_IT; + #endif + // + filesys_menu.title = TITLE_FILESYS_IT; + filesys_menu.sd_sys = SD_CARD_TEXT_IT; + filesys_menu.usb_sys = U_DISK_TEXT_IT; + + // WIFI + wifi_menu.title = WIFI_NAME_TEXT_IT; + wifi_menu.cloud = CLOSE_TEXT_IT; + wifi_menu.reconnect = WIFI_RECONNECT_TEXT_IT; + + cloud_menu.title = TITLE_CLOUD_TEXT_IT; + cloud_menu.bind = CLOUD_BINDED_IT; + cloud_menu.binded = CLOUD_BINDED_IT; + cloud_menu.unbind = CLOUD_UNBIND_IT; + cloud_menu.unbinding = CLOUD_UNBINDED_IT; + cloud_menu.disconnected = CLOUD_DISCONNECTED_IT; + cloud_menu.unbinded = CLOUD_UNBINDED_IT; + cloud_menu.disable = CLOUD_DISABLE_IT; + // + about_menu.title = ABOUT_TEXT_IT; + about_menu.type = ABOUT_TYPE_TEXT_IT; + about_menu.version = ABOUT_VERSION_TEXT_IT; + about_menu.wifi = ABOUT_WIFI_TEXT_IT; + // + fan_menu.title = FAN_TEXT_IT; + fan_menu.add = FAN_ADD_TEXT_IT; + fan_menu.dec = FAN_DEC_TEXT_IT; + fan_menu.state = FAN_TIPS1_TEXT_IT; + // + filament_menu.title = TITLE_FILAMENT_IT; + filament_menu.in = FILAMENT_IN_TEXT_IT; + filament_menu.out = FILAMENT_OUT_TEXT_IT; + filament_menu.ext1 = FILAMENT_EXT0_TEXT_IT; + filament_menu.ext2 = FILAMENT_EXT1_TEXT_IT; + filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_IT; + filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_IT; + filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_IT; + filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_IT; + filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_IT; + filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_IT; + filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_IT; + filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_IT; + filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_IT; + + // + language_menu.title = LANGUAGE_TEXT_IT; + + // + printing_menu.title = TITLE_PRINTING_IT; + printing_menu.option = PRINTING_OPERATION_IT; + printing_menu.stop = PRINTING_STOP_IT; + printing_menu.pause = PRINTING_PAUSE_IT; + printing_menu.resume = PRINTING_RESUME_IT; + + // + operation_menu.title = TITLE_OPERATION_IT; + operation_menu.pause = PRINTING_PAUSE_IT; + operation_menu.stop = PRINTING_STOP_IT; + operation_menu.temp = PRINTING_TEMP_IT; + operation_menu.fan = FAN_TEXT_IT; + operation_menu.extr = PRINTING_EXTRUDER_IT; + operation_menu.speed = PRINTING_CHANGESPEED_IT; + operation_menu.filament = FILAMENT_TEXT_IT; + operation_menu.more = PRINTING_MORE_IT; + operation_menu.move = PRINTING_MOVE_IT; + operation_menu.auto_off = AUTO_SHUTDOWN_IT; + operation_menu.manual_off = MANUAL_SHUTDOWN_IT; + // + pause_menu.title = TITLE_PAUSE_IT; + pause_menu.resume = PRINTING_RESUME_IT; + pause_menu.stop = PRINTING_STOP_IT; + pause_menu.extrude = PRINTING_EXTRUDER_IT; + pause_menu.move = PRINTING_MOVE_IT; + pause_menu.filament = FILAMENT_TEXT_IT; + pause_menu.more = PRINTING_MORE_IT; + + // + speed_menu.title = PRINTING_CHANGESPEED_IT; + speed_menu.add = ADD_TEXT_IT; + speed_menu.dec = DEC_TEXT_IT; + speed_menu.move = MOVE_SPEED_IT; + speed_menu.extrude = EXTRUDER_SPEED_IT; + speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_IT; + speed_menu.move_speed = MOVE_SPEED_STATE_IT; + // + printing_more_menu.fan = FAN_TEXT_IT; + printing_more_menu.auto_close = AUTO_SHUTDOWN_IT; + printing_more_menu.manual = MANUAL_SHUTDOWN_IT; + printing_more_menu.temp = PRINTING_TEMP_IT; + printing_more_menu.speed = PRINTING_CHANGESPEED_IT; + + print_file_dialog_menu.confirm = DIALOG_CONFIRM_IT; + print_file_dialog_menu.cancel = DIALOG_CANCLE_IT; + print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_IT; + print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_IT; + print_file_dialog_menu.retry = DIALOG_RETRY_IT; + print_file_dialog_menu.stop = DIALOG_STOP_IT; + print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_IT; + print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_IT; + print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_IT; + print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_IT; + print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_IT; + print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_IT; + print_file_dialog_menu.reprint = DIALOG_REPRINT_IT; + print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_IT; + print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_IT; + + pause_msg_menu.pausing = MESSAGE_PAUSING_IT; + pause_msg_menu.changing = MESSAGE_CHANGING_IT; + pause_msg_menu.unload = MESSAGE_UNLOAD_IT; + pause_msg_menu.waiting = MESSAGE_WAITING_IT; + pause_msg_menu.insert = MESSAGE_INSERT_IT; + pause_msg_menu.load = MESSAGE_LOAD_IT; + pause_msg_menu.purge = MESSAGE_PURGE_IT; + pause_msg_menu.resume = MESSAGE_RESUME_IT; + pause_msg_menu.heat = MESSAGE_HEAT_IT; + pause_msg_menu.heating = MESSAGE_HEATING_IT; + pause_msg_menu.option = MESSAGE_OPTION_IT; + pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_IT; + pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_IT; + eeprom_menu.title = EEPROM_SETTINGS_TITLE_IT; + eeprom_menu.store = EEPROM_SETTINGS_STORE_IT; + eeprom_menu.read = EEPROM_SETTINGS_READ_IT; + eeprom_menu.revert = EEPROM_SETTINGS_REVERT_IT; + eeprom_menu.storeTips = EEPROM_STORE_TIPS_IT; + eeprom_menu.readTips = EEPROM_READ_TIPS_IT; + eeprom_menu.revertTips = EEPROM_REVERT_TIPS_IT; + break; + + #endif // if 1 + + default: + common_menu.dialog_confirm_title = TITLE_DIALOG_CONFIRM_EN; + common_menu.text_back = BACK_TEXT_EN; + common_menu.close_machine_tips = DIALOG_CLOSE_MACHINE_EN; + common_menu.unbind_printer_tips = DIALOG_UNBIND_PRINTER_EN; + common_menu.print_special_title = PRINTING_OTHER_LANGUGE; + common_menu.pause_special_title = PRINTING_PAUSE_OTHER_LANGUGE; + common_menu.operate_special_title = PRINTING_OPERATION_OTHER_LANGUGE; + // + main_menu.title = TITLE_READYPRINT_EN; + main_menu.preheat = PREHEAT_TEXT_EN; + main_menu.move = MOVE_TEXT_EN; + main_menu.home = HOME_TEXT_EN; + main_menu.print = PRINT_TEXT_EN; + main_menu.extrude = EXTRUDE_TEXT_EN; + main_menu.leveling = LEVELING_TEXT_EN; + main_menu.autoleveling = AUTO_LEVELING_TEXT_EN; + main_menu.fan = FAN_TEXT_EN; + main_menu.set = SET_TEXT_EN; + main_menu.more = MORE_TEXT_EN; + main_menu.tool = TOOL_TEXT_EN; + // TOOL + tool_menu.title = TOOL_TEXT_EN; + tool_menu.preheat = TOOL_PREHEAT_EN; + tool_menu.extrude = TOOL_EXTRUDE_EN; + tool_menu.move = TOOL_MOVE_EN; + tool_menu.home = TOOL_HOME_EN; + tool_menu.leveling = TOOL_LEVELING_EN; + tool_menu.autoleveling = TOOL_AUTO_LEVELING_EN; + tool_menu.filament = TOOL_FILAMENT_EN; + tool_menu.more = TOOL_MORE_EN; + // + preheat_menu.adjust_title = TITLE_ADJUST_EN; + preheat_menu.title = TITLE_PREHEAT_EN; + preheat_menu.add = ADD_TEXT_EN; + preheat_menu.dec = DEC_TEXT_EN; + preheat_menu.ext1 = EXTRUDER_1_TEXT_EN; + preheat_menu.ext2 = EXTRUDER_2_TEXT_EN; + preheat_menu.hotbed = HEATBED_TEXT_EN; + preheat_menu.off = CLOSE_TEXT_EN; + // + move_menu.title = TITLE_MOVE_EN; + // + home_menu.title = TITLE_HOME_EN; + home_menu.stopmove = HOME_STOPMOVE_EN; + // + file_menu.title = TITLE_CHOOSEFILE_EN; + file_menu.page_up = PAGE_UP_TEXT_EN; + file_menu.page_down = PAGE_DOWN_TEXT_EN; + file_menu.file_loading = FILE_LOADING_EN; + file_menu.no_file = NO_FILE_EN; + file_menu.no_file_and_check = NO_FILE_EN; + // + extrude_menu.title = TITLE_EXTRUDE_EN; + extrude_menu.in = EXTRUDER_IN_TEXT_EN; + extrude_menu.out = EXTRUDER_OUT_TEXT_EN; + extrude_menu.ext1 = EXTRUDER_1_TEXT_EN; + extrude_menu.ext2 = EXTRUDER_2_TEXT_EN; + extrude_menu.low = EXTRUDE_LOW_SPEED_TEXT_EN; + extrude_menu.normal = EXTRUDE_MEDIUM_SPEED_TEXT_EN; + extrude_menu.high = EXTRUDE_HIGH_SPEED_TEXT_EN; + extrude_menu.temper_text = EXTRUDER_TEMP_TEXT_EN; + // + leveling_menu.title = TITLE_LEVELING_EN; + leveling_menu.position1 = LEVELING_POINT1_TEXT_EN; + leveling_menu.position2 = LEVELING_POINT2_TEXT_EN; + leveling_menu.position3 = LEVELING_POINT3_TEXT_EN; + leveling_menu.position4 = LEVELING_POINT4_TEXT_EN; + leveling_menu.position5 = LEVELING_POINT5_TEXT_EN; + // + set_menu.title = TITLE_SET_EN; + set_menu.filesys = FILESYS_TEXT_EN; + set_menu.wifi = WIFI_TEXT_EN; + set_menu.about = ABOUT_TEXT_EN; + set_menu.fan = FAN_TEXT_EN; + set_menu.filament = FILAMENT_TEXT_EN; + set_menu.breakpoint = BREAK_POINT_TEXT_EN; + set_menu.motoroff = MOTOR_OFF_TEXT_EN; + set_menu.motoroffXY = MOTOR_OFF_XY_TEXT_EN; + set_menu.language = LANGUAGE_TEXT_EN; + set_menu.shutdown = SHUTDOWN_TEXT_EN; + set_menu.machine_para = MACHINE_PARA_EN; + set_menu.eepromSet = EEPROM_SETTINGS_EN; + // + more_menu.title = TITLE_MORE_EN; + #if ENABLED(USER_CMD_1_ENABLE) + more_menu.custom1 = MORE_CUSTOM1_TEXT_EN; + #endif + #if ENABLED(USER_CMD_2_ENABLE) + more_menu.custom2 = MORE_CUSTOM2_TEXT_EN; + #endif + #if ENABLED(USER_CMD_3_ENABLE) + more_menu.custom3 = MORE_CUSTOM3_TEXT_EN; + #endif + #if ENABLED(USER_CMD_4_ENABLE) + more_menu.custom4 = MORE_CUSTOM4_TEXT_EN; + #endif + #if ENABLED(USER_CMD_5_ENABLE) + more_menu.custom5 = MORE_CUSTOM5_TEXT_EN; + #endif + #if ENABLED(USER_CMD_6_ENABLE) + more_menu.custom6 = MORE_CUSTOM6_TEXT_EN; + #endif + #if ENABLED(USER_CMD_7_ENABLE) + more_menu.custom7 = MORE_CUSTOM7_TEXT_EN; + #endif + // + filesys_menu.title = TITLE_FILESYS_EN; + filesys_menu.sd_sys = SD_CARD_TEXT_EN; + filesys_menu.usb_sys = U_DISK_TEXT_EN; + // WIFI + wifi_menu.title = WIFI_TEXT; + wifi_menu.cloud = CLOUD_TEXT_EN; + wifi_menu.reconnect = WIFI_RECONNECT_TEXT_EN; + + cloud_menu.title = TITLE_CLOUD_TEXT_EN; + cloud_menu.bind = CLOUD_BINDED_EN; + cloud_menu.binded = CLOUD_BINDED_EN; + cloud_menu.unbind = CLOUD_UNBIND_EN; + cloud_menu.unbinding = CLOUD_UNBINDED_EN; + cloud_menu.disconnected = CLOUD_DISCONNECTED_EN; + cloud_menu.unbinded = CLOUD_UNBINDED_EN; + cloud_menu.disable = CLOUD_DISABLE_EN; + // + about_menu.title = TITLE_ABOUT_EN; + about_menu.type = ABOUT_TYPE_TEXT_EN; + about_menu.version = ABOUT_VERSION_TEXT_EN; + about_menu.wifi = ABOUT_WIFI_TEXT_EN; + // + fan_menu.title = TITLE_FAN_EN; + fan_menu.add = FAN_ADD_TEXT_EN; + fan_menu.dec = FAN_DEC_TEXT_EN; + fan_menu.state = FAN_TIPS1_TEXT_EN; + // + filament_menu.title = TITLE_FILAMENT_EN; + filament_menu.in = FILAMENT_IN_TEXT_EN; + filament_menu.out = FILAMENT_OUT_TEXT_EN; + filament_menu.ext1 = FILAMENT_EXT0_TEXT_EN; + filament_menu.ext2 = FILAMENT_EXT1_TEXT_EN; + filament_menu.ready_replace = FILAMENT_CHANGE_TEXT_EN; + filament_menu.filament_dialog_load_heat = FILAMENT_DIALOG_LOAD_HEAT_TIPS_EN; + filament_menu.filament_dialog_load_heat_confirm = FILAMENT_DIALOG_LOAD_CONFIRM1_TIPS_EN; + filament_menu.filament_dialog_loading = FILAMENT_DIALOG_LOADING_TIPS_EN; + filament_menu.filament_dialog_load_completed = FILAMENT_DIALOG_LOAD_COMPLETE_TIPS_EN; + filament_menu.filament_dialog_unload_heat = FILAMENT_DIALOG_UNLOAD_HEAT_TIPS_EN; + filament_menu.filament_dialog_unload_heat_confirm = FILAMENT_DIALOG_UNLOAD_CONFIRM_TIPS_EN; + filament_menu.filament_dialog_unloading = FILAMENT_DIALOG_UNLOADING_TIPS_EN; + filament_menu.filament_dialog_unload_completed = FILAMENT_DIALOG_UNLOAD_COMPLETE_TIPS_EN; + + // + language_menu.title = TITLE_LANGUAGE_EN; + language_menu.next = PAGE_DOWN_TEXT_EN; + language_menu.up = PAGE_UP_TEXT_EN; + // + printing_menu.title = TITLE_PRINTING_EN; + printing_menu.option = PRINTING_OPERATION_EN; + printing_menu.stop = PRINTING_STOP_EN; + printing_menu.pause = PRINTING_PAUSE_EN; + printing_menu.resume = PRINTING_RESUME_EN; + + // + operation_menu.title = TITLE_OPERATION_EN; + operation_menu.pause = PRINTING_PAUSE_EN; + operation_menu.stop = PRINTING_STOP_EN; + operation_menu.temp = PRINTING_TEMP_EN; + operation_menu.fan = FAN_TEXT_EN; + operation_menu.extr = PRINTING_EXTRUDER_EN; + operation_menu.speed = PRINTING_CHANGESPEED_EN; + operation_menu.filament = FILAMENT_TEXT_EN; + operation_menu.more = PRINTING_MORE_EN; + operation_menu.move = PRINTING_MOVE_EN; + operation_menu.auto_off = AUTO_SHUTDOWN_EN; + operation_menu.manual_off = MANUAL_SHUTDOWN_EN; + // + pause_menu.title = TITLE_PAUSE_EN; + pause_menu.resume = PRINTING_RESUME_EN; + pause_menu.stop = PRINTING_STOP_EN; + pause_menu.extrude = PRINTING_EXTRUDER_EN; + pause_menu.move = PRINTING_MOVE_EN; + pause_menu.filament = FILAMENT_TEXT_EN; + pause_menu.more = PRINTING_MORE_EN; + + // + speed_menu.title = TITLE_CHANGESPEED_EN; + speed_menu.add = ADD_TEXT_EN; + speed_menu.dec = DEC_TEXT_EN; + speed_menu.move = MOVE_SPEED_EN; + speed_menu.extrude = EXTRUDER_SPEED_EN; + speed_menu.extrude_speed = EXTRUDER_SPEED_STATE_EN; + speed_menu.move_speed = MOVE_SPEED_STATE_EN; + // + printing_more_menu.title = TITLE_MORE_EN; + printing_more_menu.fan = FAN_TEXT_EN; + printing_more_menu.auto_close = AUTO_SHUTDOWN_EN; + printing_more_menu.manual = MANUAL_SHUTDOWN_EN; + printing_more_menu.speed = PRINTING_CHANGESPEED_EN; + printing_more_menu.temp = PRINTING_TEMP_EN; + + print_file_dialog_menu.confirm = DIALOG_CONFIRM_EN; + print_file_dialog_menu.cancel = DIALOG_CANCLE_EN; + print_file_dialog_menu.print_file = DIALOG_PRINT_MODEL_EN; + print_file_dialog_menu.cancel_print = DIALOG_CANCEL_PRINT_EN; + print_file_dialog_menu.retry = DIALOG_RETRY_EN; + print_file_dialog_menu.stop = DIALOG_STOP_EN; + print_file_dialog_menu.no_file_print_tips = DIALOG_ERROR_TIPS1_EN; + print_file_dialog_menu.print_from_breakpoint = DIALOG_REPRINT_FROM_BREAKPOINT_EN; + print_file_dialog_menu.close_machine_error = DIALOG_ERROR_TIPS2_EN; + print_file_dialog_menu.filament_no_press = DIALOG_FILAMENT_NO_PRESS_EN; + print_file_dialog_menu.print_finish = DIALOG_PRINT_FINISH_EN; + print_file_dialog_menu.print_time = DIALOG_PRINT_TIME_EN; + print_file_dialog_menu.reprint = DIALOG_REPRINT_EN; + print_file_dialog_menu.wifi_enable_tips = DIALOG_WIFI_ENABLE_TIPS_EN; + print_file_dialog_menu.machinePausingTips = DIALOG_PAUSING_TIPS_EN; + + pause_msg_menu.pausing = MESSAGE_PAUSING_EN; + pause_msg_menu.changing = MESSAGE_CHANGING_EN; + pause_msg_menu.unload = MESSAGE_UNLOAD_EN; + pause_msg_menu.waiting = MESSAGE_WAITING_EN; + pause_msg_menu.insert = MESSAGE_INSERT_EN; + pause_msg_menu.load = MESSAGE_LOAD_EN; + pause_msg_menu.purge = MESSAGE_PURGE_EN; + pause_msg_menu.resume = MESSAGE_RESUME_EN; + pause_msg_menu.heat = MESSAGE_HEAT_EN; + pause_msg_menu.heating = MESSAGE_HEATING_EN; + pause_msg_menu.option = MESSAGE_OPTION_EN; + pause_msg_menu.purgeMore = MESSAGE_PURGE_MORE_EN; + pause_msg_menu.continuePrint = MESSAGE_CONTINUE_PRINT_EN; + eeprom_menu.title = EEPROM_SETTINGS_TITLE_EN; + eeprom_menu.store = EEPROM_SETTINGS_STORE_EN; + eeprom_menu.read = EEPROM_SETTINGS_READ_EN; + eeprom_menu.revert = EEPROM_SETTINGS_REVERT_EN; + eeprom_menu.storeTips = EEPROM_STORE_TIPS_EN; + eeprom_menu.readTips = EEPROM_READ_TIPS_EN; + eeprom_menu.revertTips = EEPROM_REVERT_TIPS_EN; + break; + } +} + +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.h b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.h new file mode 100644 index 0000000..7314da4 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/tft_multi_language.h @@ -0,0 +1,865 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "tft_Language_en.h" +#include "tft_Language_s_cn.h" +#include "tft_Language_t_cn.h" +#include "tft_Language_ru.h" +#include "tft_Language_fr.h" +#include "tft_Language_sp.h" +#include "tft_Language_it.h" + +extern void disp_language_init(); + +#define LANG_SIMPLE_CHINESE 1 +#define LANG_COMPLEX_CHINESE 2 +#define LANG_ENGLISH 3 +#define LANG_JAPAN 4 +#define LANG_GERMAN 5 +#define LANG_FRENCH 6 +#define LANG_RUSSIAN 7 +#define LANG_KOREAN 8 +#define LANG_TURKISH 9 +#define LANG_SPANISH 10 +#define LANG_GREEK 11 +#define LANG_ITALY 12 +#define LANG_PORTUGUESE 13 + +#define MULTI_LANGUAGE_ENABLE 1 +#define MULTI_LANGUAGE_DISABLE 0 + +typedef struct machine_common_disp{ + const char *default_value; + + const char *next; + const char *previous; + + const char *MachineConfigTitle; + const char *MachineType; + const char *Stroke; + const char *HomeDir; + const char *EndStopType; + const char *FilamentConf; + + const char *MachineTypeConfTitle; + const char *xyz; + const char *delta; + const char *corexy; + + const char *StrokeConfTitle; + const char *xStroke; + const char *yStroke; + const char *zStroke; + + const char *xmin; + const char *ymin; + const char *zmin; + + const char *HomeDirConfTitle; + const char *xHomeDir; + const char *yHomeDir; + const char *zHomeDir; + const char *min; + const char *max; + + const char *EndstopConfTitle; + const char *xEndstop_min; + const char *yEndstop_min; + const char *zEndstop_min; + const char *xEndstop_max; + const char *yEndstop_max; + const char *zEndstop_max; + const char *FilamentEndstop; + const char *LevelingEndstop; + const char *opened; + const char *closed; + + const char *FilamentConfTitle; + const char *InLength; + const char *InSpeed; + const char *FilamentTemperature; + const char *OutLength; + const char *OutSpeed; + + const char *LevelingParaConfTitle; + const char *LevelingParaConf; + const char *LevelingManuPosConf; + const char *LevelingAutoCommandConf; + const char *LevelingAutoZoffsetConf; + const char *LevelingTouchmiConf; + const char *TouchmiInit; + const char *TouchmiOffsetpos; + const char *TouchmiOffsetneg; + const char *TouchmiSave; + const char *TouchmiTest; + + const char *BLTouchLevelingConfTitle; + const char *BLTouchLevelingConf; + const char *BLTouchInit; + const char *BLTouchOffsetpos; + const char *BLTouchOffsetneg; + const char *BLTouchSave; + const char *BLTouchTest; + + const char *LevelingSubConfTitle; + const char *AutoLevelEnable; + const char *BLtouchEnable; + const char *ProbePort; + const char *ProbeXoffset; + const char *ProbeYoffset; + const char *ProbeZoffset; + const char *ProbeXYspeed; + const char *ProbeZspeed; + const char *enable; + const char *disable; + const char *locked; + const char *z_min; + const char *z_max; + + const char *LevelingSubDeltaConfTitle; + const char *MachineRadius; + const char *DiagonalRod; + const char *PrintableRadius; + const char *DeltaHeight; + const char *SmoothRodOffset; + const char *EffectorOffset; + const char *CalibrationRadius; + + const char *LevelingSubXYZConfTitle; + + const char *TemperatureConfTitle; + const char *NozzleConf; + const char *HotBedConf; + const char *PreheatTemperConf; + + const char *NozzleCnt; + const char *NozzleConfTitle; + const char *NozzleType; + const char *NozzleAdjustType; + const char *NozzleMinTemperature; + const char *NozzleMaxTemperature; + const char *Extrude_Min_Temper; + + const char *HotbedEnable; + const char *HotbedConfTitle; + const char *HotbedAjustType; + const char *HotbedMinTemperature; + const char *HotbedMaxTemperature; + + const char *MotorConfTitle; + const char *MaxFeedRateConf; + const char *AccelerationConf; + const char *JerkConf; + const char *StepsConf; + const char *MotorDirConf; + const char *HomeFeedRateConf; + const char *TMCcurrentConf; + const char *TMCStepModeConf; + const char *HomingSensitivityConf; + + const char *MaxFeedRateConfTitle; + const char *XMaxFeedRate; + const char *YMaxFeedRate; + const char *ZMaxFeedRate; + const char *E0MaxFeedRate; + const char *E1MaxFeedRate; + + const char *AccelerationConfTitle; + const char *PrintAcceleration; + const char *RetractAcceleration; + const char *TravelAcceleration; + const char *X_Acceleration; + const char *Y_Acceleration; + const char *Z_Acceleration; + const char *E0_Acceleration; + const char *E1_Acceleration; + + const char *JerkConfTitle; + const char *X_Jerk; + const char *Y_Jerk; + const char *Z_Jerk; + const char *E_Jerk; + + const char *StepsConfTitle; + const char *X_Steps; + const char *Y_Steps; + const char *Z_Steps; + const char *E0_Steps; + const char *E1_Steps; + + const char *TmcCurrentConfTitle; + const char *X_Current; + const char *Y_Current; + const char *Z_Current; + const char *E0_Current; + const char *E1_Current; + + const char *TmcStepModeConfTitle; + const char *X_StepMode; + const char *Y_StepMode; + const char *Z_StepMode; + const char *E0_StepMode; + const char *E1_StepMode; + + const char *HomingSensitivityConfTitle; + const char *X_Sensitivity; + const char *Y_Sensitivity; + const char *Z_Sensitivity; + const char *Z2_Sensitivity; + + const char *MotorDirConfTitle; + const char *X_MotorDir; + const char *Y_MotorDir; + const char *Z_MotorDir; + const char *E0_MotorDir; + const char *E1_MotorDir; + const char *Invert_1; + const char *Invert_0; + + const char *HomeFeedRateConfTitle; + const char *XY_HomeFeedRate; + const char *Y_HomeFeedRate; + const char *Z_HomeFeedRate; + + const char *AdvancedConfTitle; + const char *PwrOffDection; + const char *PwrOffAfterPrint; + const char *HaveUps; + const char *Z2andZ2Endstop; + const char *EnablePinsInvert; + const char *PausePosition; + const char *WifiSettings; + const char *EncoderSettings; + + const char *Z2ConfTitle; + const char *Z2Enable; + const char *Z2EndstopEnable; + const char *Z2Port; + + const char *EnablePinsInvertTitle; + const char *XInvert; + const char *YInvert; + const char *ZInvert; + const char *EInvert; + + const char *key_1; + const char *key_2; + const char *key_3; + const char *key_4; + const char *key_5; + const char *key_6; + const char *key_7; + const char *key_8; + const char *key_9; + const char *key_0; + const char *key_point; + const char *key_back; + const char *key_reset; + const char *key_confirm; + const char *negative; + const char *low_level; + const char *high_level; + + const char *PausePosText; + const char *xPos; + const char *yPos; + const char *zPos; + + const char *WifiConfTitle; + const char *wifiMode; + const char *wifiName; + const char *wifiPassWord; + const char *wifiCloud; + const char *wifiConfig; + const char *wifiEdit; + const char *wifiConfigTips; + + const char *OffsetConfTitle; + const char *Xoffset; + const char *Yoffset; + const char *Zoffset; + + const char *EncoderConfTitle; + const char *EncoderConfText; + +} machine_common_def; + +extern machine_common_def machine_menu; + +typedef struct common_menu_disp { + const char *text_back; + const char *dialog_confirm_title; + const char *close_machine_tips; + const char *unbind_printer_tips; + const char *print_special_title; + const char *pause_special_title; + const char *operate_special_title; + const char *next; + const char *previous; +} common_menu_def; + +extern common_menu_def common_menu; + +typedef struct main_menu_disp { + const char *title; + const char *preheat; + const char *move; + const char *home; + const char *print; + const char *extrude; + const char *leveling; + const char *autoleveling; + const char *fan; + const char *set; + const char *tool; + const char *more; + const char *machine_para; +} main_menu_def; + +extern main_menu_def main_menu; + +typedef struct preheat_menu_disp { + const char *adjust_title; + const char *title; + const char *add; + const char *dec; + const char *ext1; + const char *ext2; + const char *hotbed; + const char *off; + const char *step_1c; + const char *step_5c; + const char *step_10c; + const char *back; + + const char *value_state; + + const char *dialog_tips; + +} preheat_menu_def; + +extern preheat_menu_def preheat_menu; + +typedef struct move_menu_disp { + const char *title; + const char *x_add; + const char *x_dec; + const char *y_add; + const char *y_dec; + const char *z_add; + const char *z_dec; + const char *step_001mm; + const char *step_005mm; + const char *step_01mm; + const char *step_1mm; + const char *step_10mm; + const char *back; +} move_menu_def; + +extern move_menu_def move_menu; + +typedef struct home_menu_disp { + const char *title; + const char *home_all; + const char *home_x; + const char *home_y; + const char *home_z; + const char *stopmove; + const char *back; +} home_menu_def; + +extern home_menu_def home_menu; + +typedef struct touchmi_menu_disp { + const char *title; + const char *init; + const char *zoffsetpos; + const char *zoffsetneg; + const char *test; + const char *save; +} touchmi_menu_def; + +extern touchmi_menu_def touchmi_menu; + +typedef struct file_menu_disp { + const char *title; + const char *page_up; + const char *page_down; + const char *back; + + const char *file_loading; + const char *no_file; + const char *no_file_and_check; + +} file_menu_def; + +extern file_menu_def file_menu; + +typedef struct extrude_menu_disp { + const char *title; + const char *in; + const char *out; + const char *ext1; + const char *ext2; + const char *step_1mm; + const char *step_5mm; + const char *step_10mm; + const char *low; + const char *normal; + const char *high; + const char *back; + + const char *count_value_mm; + const char *count_value_cm; + const char *count_value_m; + const char *temp_value; + const char *temper_text; +} extrude_menu_def; + +extern extrude_menu_def extrude_menu; + +typedef struct leveling_menu_disp { + const char *title; + const char *position1; + const char *position2; + const char *position3; + const char *position4; + const char *position5; + + char *back; +} leveling_menu_def; + +extern leveling_menu_def leveling_menu; + +typedef struct set_menu_disp { + const char *title; + const char *filesys; + const char *wifi; + const char *about; + const char *fan; + const char *filament; + const char *breakpoint; + const char *motoroff; + const char *motoroffXY; + const char *shutdown; + const char *language; + const char *machine_para; + const char *eepromSet; + const char *back; +} set_menu_def; + +extern set_menu_def set_menu; + +typedef struct filesys_menu_disp { + const char *title; + const char *filesys; + const char *sd_sys; + const char *usb_sys; + const char *back; +} filesys_menu_def; + +extern filesys_menu_def filesys_menu; + +typedef struct more_menu_disp { + const char *title; + const char *custom1; + const char *custom2; + const char *custom3; + const char *custom4; + const char *custom5; + const char *custom6; + const char *custom7; + const char *back; +} more_menu_def; + +extern more_menu_def more_menu; + +typedef struct wifi_menu_disp { + const char *title; + const char *ip; + const char *wifi; + const char *key; + const char *state_ap; + const char *state_sta; + const char *cloud; + const char *connected; + const char *disconnected; + const char *exception; + const char *back; + const char *reconnect; +} wifi_menu_def; + +extern wifi_menu_def wifi_menu; + +typedef struct cloud_menu_disp { + const char *title; + const char *unbind; + const char *unbinding; + const char *unbinded; + const char *bind; + const char *binding; + const char *binded; + const char *disable; + const char *disconnected; + const char *back; + const char *unbind_printer_tips; +} cloud_menu_def; + +extern cloud_menu_def cloud_menu; + +typedef struct about_menu_disp { + const char *title; + const char *type_name; + const char *firmware_v; + const char *type; + const char *version; + const char *wifi; + const char *type_robin; + const char *type_robin_mini; + const char *back; +} about_menu_def; + +extern about_menu_def about_menu; + +typedef struct fan_menu_disp { + const char *title; + const char *add; + const char *dec; + const char *full; + const char *half; + const char *off; + const char *back; + + const char *state; + const char *state_value; +} fan_menu_def; + +extern fan_menu_def fan_menu; + +typedef struct filament_menu_disp { + const char *title; + const char *in; + const char *out; + const char *ext1; + const char *ext2; + const char *back; + const char *stat_temp; + const char *ready_replace; + const char *replacing; + const char *loading; + const char *unloading; + const char *heating; + const char *complete_and_back; + const char *filament_dialog_load_heat; + const char *filament_dialog_unload_heat; + const char *filament_dialog_load_heat_confirm; + const char *filament_dialog_unload_heat_confirm; + const char *filament_dialog_loading; + const char *filament_dialog_unloading; + const char *filament_dialog_load_completed; + const char *filament_dialog_unload_completed; + const char *filament_dialog_ok; + const char *filament_dialog_back; +} filament_menu_def; + +extern filament_menu_def filament_menu; + +typedef struct language_menu { + const char *title; + const char *chinese_s; + const char *chinese_t; + const char *english; + const char *russian; + const char *japan; + const char *italy; + const char *german; + const char *spanish; + const char *korean; + const char *french; + const char *brazil; + const char *portuguese; + const char *next; + const char *up; + const char *back; +} language_menu_def; + +extern language_menu_def language_menu; + +typedef struct printing_menu_disp { + const char *title; + const char *option; + const char *temp1; + const char *temp2; + const char *bed_temp; + const char *fan_speed; + const char *pause; + const char *resume; + const char *stop; +} printing_menu_def; + +extern printing_menu_def printing_menu; + +typedef struct operation_menu_disp { + const char *title; + const char *pause; + const char *stop; + const char *temp; + const char *fan; + const char *filament; + const char *extr; + const char *speed; + const char *move; + const char *more; + const char *auto_off; + const char *manual_off; + const char *back; + const char *babystep; +} operation_menu_def; + +extern operation_menu_def operation_menu; + +typedef struct pause_menu_disp { + const char *title; + const char *resume; + const char *stop; + const char *extrude; + const char *move; + const char *filament; + const char *more; +} pause_menu_def; + +extern pause_menu_def pause_menu; + +typedef struct speed_menu_disp { + const char *title; + const char *add; + const char *dec; + const char *extrude; + const char *move; + const char *step_1percent; + const char *step_5percent; + const char *step_10percent; + const char *back; + const char *move_speed; + const char *extrude_speed; +} speed_menu_def; + +extern speed_menu_def speed_menu; + +typedef struct printing_more_menu_disp { + const char *title; + const char *fan; + const char *auto_close; + const char *manual; + const char *temp; + const char *speed; + const char *back; +} printing_more_menu_def; + +extern printing_more_menu_def printing_more_menu; + +typedef struct dialog_menu_disp { + const char *confirm_title; + + const char *error1_repint_no_file; + const char *error2_communication_fail; + const char *error3_filename_too_long; + const char *error4_no_file; + const char *error5_check_filesys; + + const char *tip1_print_file; + const char *tip2_stop_file; +} dialog_menu_def; + +extern dialog_menu_def dialog_menu; + +typedef struct print_file_dialog_disp { + const char *title; + const char *confirm; + const char *cancel; + const char *print_file; + const char *cancel_print; + const char *retry; + const char *stop; + const char *no_file_print_tips; + const char *print_from_breakpoint; + const char *file_name_too_long_error; + const char *close_machine_error; + const char *filament_no_press; + const char *print_finish; + const char *print_time; + const char *reprint; + const char *wifi_enable_tips; + const char *machinePausingTips; +} print_file_dialog_menu_def; + +extern print_file_dialog_menu_def print_file_dialog_menu; + +typedef struct tool_menu_disp { + const char *title; + const char *preheat; + const char *extrude; + const char *move; + const char *home; + const char *leveling; + const char *autoleveling; + const char *filament; + const char *more; + const char *back; +} tool_menu_def; + +extern tool_menu_def tool_menu; + +typedef struct MachinePara_menu_disp { + const char *title; + const char *MachineSetting; + const char *MotorSetting; + const char *leveling; + const char *AdvanceSetting; +} MachinePara_menu_def; + +extern MachinePara_menu_def MachinePara_menu; + +typedef struct pause_msg_disp { + const char *pausing; + const char *changing; + const char *unload; + const char *waiting; + const char *insert; + const char *load; + const char *purge; + const char *resume; + const char *heat; + const char *heating; + const char *option; + const char *purgeMore; + const char *continuePrint; +} pause_msg_def; + +extern pause_msg_def pause_msg_menu; + +typedef struct eeprom_disp{ + const char *title; + const char *store; + const char *read; + const char *revert; + const char *storeTips; + const char *readTips; + const char *revertTips; +} eeprom_def; + +extern eeprom_def eeprom_menu; +/*****************************************/ +// +#define TEXT_VALUE "%d/%d" + +#define TEXT_VALUE_T ": %d℃" +#define TEXT_VALUE_mm ": %dmm" +#define TEXT_VALUE_cm ": %dcm" +#define TEXT_VALUE_m ": %dm" + +#define TEMP_UNIT_SYBOL "%d℃" +#define FLOAT_TEMP_UNIT_SYBOL "%.1f℃" + +#define TEXT_1C "1℃" +#define TEXT_5C "5℃" +#define TEXT_10C "10℃" + +#define AXIS_X_ADD_TEXT "X+" +#define AXIS_X_DEC_TEXT "X-" +#define AXIS_Y_ADD_TEXT "Y+" +#define AXIS_Y_DEC_TEXT "Y-" +#define AXIS_Z_ADD_TEXT "Z+" +#define AXIS_Z_DEC_TEXT "Z-" +#define TEXT_001MM "0.01 mm" +#define TEXT_005MM "0.05 mm" +#define TEXT_01MM "0.1 mm" +#define TEXT_1MM "1 mm" +#define TEXT_10MM "10 mm" + +#define EXTRUDE_1MM_TEXT "1 mm" +#define EXTRUDE_5MM_TEXT "5 mm" +#define EXTRUDE_10MM_TEXT "10 mm" + +#define STEP_1PERCENT "1%" +#define STEP_5PERCENT "5%" +#define STEP_10PERCENT "10%" + +#define LANGUAGE_S_CN "简体" +#define LANGUAGE_T_CN "繁体" +#define LANGUAGE_EN "English" +#define LANGUAGE_JP "日本語" +#define LANGUAGE_GE "Deutsch" +#define LANGUAGE_FR "français" +#define LANGUAGE_IT "Italiano" +#define LANGUAGE_PR "português" +#define LANGUAGE_KR "Korean" +#define LANGUAGE_BR "Brazil" +#define LANGUAGE_RU "русский" +#define LANGUAGE_SP "español" + +#define HOME_X_TEXT "X" +#define HOME_Y_TEXT "Y" +#define HOME_Z_TEXT "Z" +#define HOME_ALL_TEXT "All" + +#define TM_INIT "Init" +#define TM_ZOFFSETPOS "Offset +" +#define TM_ZOFFSETNEG "Offset -" +#define TM_SAVE "Save" +#define TM_TEST "Test" + +//#if defined(MKS_ROBIN_NANO) +#define ABOUT_TYPE_TEXT "MKS Robin Pro" + +#define ABOUT_VERSION_TEXT "1.0.0" + +#define FAN_OPEN_TEXT "100%" +#define FAN_HALF_TEXT "50%" +#define FAN_CLOSE_TEXT "0%" + +#define WIFI_TEXT "WIFI" +#define WIFI_IP_TEXT "IP: " +#define WIFI_NAME_TEXT "WiFi: " +#define WIFI_KEY_TEXT "Key: " +#define WIFI_STATE_AP_TEXT "State: AP" +#define WIFI_STATE_STA_TEXT "State: STA" +#define WIFI_CONNECTED_TEXT "Connected" +#define WIFI_DISCONNECTED_TEXT "Disconnected" +#define WIFI_EXCEPTION_TEXT "Exception" + +#define FILAMENT_TIPS2_TEXT "T:" + +#define DIALOG_UPLOAD_ING_EN "Uploading......" +#define DIALOG_UPLOAD_ERROR_EN "Upload error" +#define DIALOG_UPLOAD_FINISH_EN "Upload finished" +#define DIALOG_UPLOAD_SIZE_EN "Size" +#define DIALOG_UPLOAD_TIME_EN "Time" +#define DIALOG_UPLOAD_SPEED_EN "Speed" +#define DIALOG_UPDATE_WIFI_FIRMWARE_EN "Updating wifi model firmware" +#define DIALOG_UPDATE_WIFI_WEB_EN "Updating wifi model web data" +#define DIALOG_UPDATE_NO_DEVICE_EN "Please check\nwether memory device insert!" + +#define ZOFFSET_STEP001 "0.01 mm" +#define ZOFFSET_STEP01 "0.1 mm" +#define ZOFFSET_STEP1 "1 mm" diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.cpp b/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.cpp new file mode 100644 index 0000000..d10d10e --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.cpp @@ -0,0 +1,526 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "tft_lvgl_configuration.h" + +#if ENABLED(MKS_WIFI_MODULE) + +#include "draw_ui.h" +#include "wifiSerial.h" + +#ifdef __STM32F1__ + + #include <libmaple/libmaple.h> + #include <libmaple/gpio.h> + #include <libmaple/timer.h> + #include <libmaple/usart.h> + #include <libmaple/ring_buffer.h> + + #include "../../../../MarlinCore.h" + + DEFINE_WFSERIAL(WifiSerial1, 1); + + WifiSerial::WifiSerial(usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin) { + this->usart_device = usart_device; + this->tx_pin = tx_pin; + this->rx_pin = rx_pin; + } + + /** + * Set up / tear down + */ + #if STM32_MCU_SERIES == STM32_SERIES_F1 + /* F1 MCUs have no GPIO_AFR[HL], so turn off PWM if there's a conflict + * on this GPIO bit. */ + static void disable_timer_if_necessary(timer_dev *dev, uint8 ch) { + if (dev) timer_set_mode(dev, ch, TIMER_DISABLED); + } + static void usart_enable_no_irq(usart_dev *usart_device, bool with_irq) { + if (with_irq) usart_enable(usart_device); + else { + usart_reg_map *regs = usart_device->regs; + regs->CR1 |= (USART_CR1_TE | USART_CR1_RE);// don't change the word length etc, and 'or' in the patten not overwrite |USART_CR1_M_8N1); + regs->CR1 |= USART_CR1_UE; + } + } + + #elif STM32_MCU_SERIES == STM32_SERIES_F2 || STM32_MCU_SERIES == STM32_SERIES_F4 + #define disable_timer_if_necessary(dev, ch) ((void)0) + + static void usart_enable_no_irq(usart_dev *usart_device, bool with_irq) { + if (with_irq) usart_enable(usart_device); + else { + usart_reg_map *regs = usart_device->regs; + regs->CR1 |= (USART_CR1_TE | USART_CR1_RE);// don't change the word length etc, and 'or' in the patten not overwrite |USART_CR1_M_8N1); + regs->CR1 |= USART_CR1_UE; + } + } + #else + #warning "Unsupported STM32 series; timer conflicts are possible" + #define usart_enable_no_irq(X, Y) usart_enable(X) + #endif + + void WifiSerial::begin(uint32 baud) { begin(baud, SERIAL_8N1); } + + /** + * Roger Clark. + * Note. The config parameter is not currently used. This is a work in progress. + * Code needs to be written to set the config of the hardware serial control register in question. + */ + + void WifiSerial::begin(uint32 baud, uint8_t config) { + //ASSERT(baud <= this->usart_device->max_baud); // Roger Clark. Assert doesn't do anything useful, we may as well save the space in flash and ram etc + + if (baud > this->usart_device->max_baud) return; + + const stm32_pin_info *txi = &PIN_MAP[this->tx_pin], + *rxi = &PIN_MAP[this->rx_pin]; + + disable_timer_if_necessary(txi->timer_device, txi->timer_channel); + + usart_init(this->usart_device); + + // Reinitialize the receive buffer, mks_esp8266 fixed data frame length is 1k bytes + rb_init(this->usart_device->rb, WIFI_RX_BUF_SIZE, wifiRxBuf); + + usart_config_gpios_async(this->usart_device, + rxi->gpio_device, rxi->gpio_bit, + txi->gpio_device, txi->gpio_bit, + config); + usart_set_baud_rate(this->usart_device, USART_USE_PCLK, baud); + usart_enable_no_irq(this->usart_device, baud == WIFI_BAUDRATE); + } + + void WifiSerial::end(void) { + usart_disable(this->usart_device); + } + + int WifiSerial::available(void) { + return usart_data_available(this->usart_device); + } + + // + // I/O + // + + int WifiSerial::read(void) { + if (usart_data_available(usart_device) <= 0) return -1; + return usart_getc(usart_device); + } + + int WifiSerial::write(unsigned char ch) { + usart_putc(this->usart_device, ch); + return 1; + } + + int WifiSerial::wifi_rb_is_full(void) { + return rb_is_full(this->usart_device->rb); + } + +#else + + WifiSerial WifiSerial1(USART1); + + void WifiSerial::setRx(uint32_t _rx) + { + _serial.pin_rx = digitalPinToPinName(_rx); + } + + void WifiSerial::setTx(uint32_t _tx) + { + _serial.pin_tx = digitalPinToPinName(_tx); + } + + void WifiSerial::setRx(PinName _rx) + { + _serial.pin_rx = _rx; + } + + void WifiSerial::setTx(PinName _tx) + { + _serial.pin_tx = _tx; + } + + void WifiSerial::init(PinName _rx, PinName _tx) + { + if (_rx == _tx) { + _serial.pin_rx = NC; + } else { + _serial.pin_rx = _rx; + } + _serial.pin_tx = _tx; + _serial.rx_buff = wifiRxBuf; + _serial.rx_head = 0; + _serial.rx_tail = 0; + _serial.tx_buff = wifiTxBuf; + _serial.tx_head = 0; + _serial.tx_tail = 0; + } + + WifiSerial::WifiSerial(void *peripheral) + { + // If PIN_SERIALy_RX is not defined assume half-duplex + _serial.pin_rx = NC; + // If Serial is defined in variant set + // the Rx/Tx pins for com port if defined + #if defined(Serial) && defined(PIN_SERIAL_TX) + if ((void *)this == (void *)&Serial) { + #if defined(PIN_SERIAL_RX) + setRx(PIN_SERIAL_RX); + #endif + setTx(PIN_SERIAL_TX); + } else + #endif + #if defined(PIN_SERIAL1_TX) && defined(USART1_BASE) + if (peripheral == USART1) { + #if defined(PIN_SERIAL1_RX) + setRx(PIN_SERIAL1_RX); + #endif + setTx(PIN_SERIAL1_TX); + } else + #endif + #if defined(PIN_SERIAL2_TX) && defined(USART2_BASE) + if (peripheral == USART2) { + #if defined(PIN_SERIAL2_RX) + setRx(PIN_SERIAL2_RX); + #endif + setTx(PIN_SERIAL2_TX); + } else + #endif + #if defined(PIN_SERIAL3_TX) && defined(USART3_BASE) + if (peripheral == USART3) { + #if defined(PIN_SERIAL3_RX) + setRx(PIN_SERIAL3_RX); + #endif + setTx(PIN_SERIAL3_TX); + } else + #endif + #if defined(PIN_SERIAL4_TX) &&\ + (defined(USART4_BASE) || defined(UART4_BASE)) + #if defined(USART4_BASE) + if (peripheral == USART4) + #elif defined(UART4_BASE) + if (peripheral == UART4) + #endif + { + #if defined(PIN_SERIAL4_RX) + setRx(PIN_SERIAL4_RX); + #endif + setTx(PIN_SERIAL4_TX); + } else + #endif + #if defined(PIN_SERIAL5_TX) &&\ + (defined(USART5_BASE) || defined(UART5_BASE)) + #if defined(USART5_BASE) + if (peripheral == USART5) + #elif defined(UART5_BASE) + if (peripheral == UART5) + #endif + { + #if defined(PIN_SERIAL5_RX) + setRx(PIN_SERIAL5_RX); + #endif + setTx(PIN_SERIAL5_TX); + } else + #endif + #if defined(PIN_SERIAL6_TX) && defined(USART6_BASE) + if (peripheral == USART6) { + #if defined(PIN_SERIAL6_RX) + setRx(PIN_SERIAL6_RX); + #endif + setTx(PIN_SERIAL6_TX); + } else + #endif + #if defined(PIN_SERIAL7_TX) &&\ + (defined(USART7_BASE) || defined(UART7_BASE)) + #if defined(USART7_BASE) + if (peripheral == USART7) + #elif defined(UART7_BASE) + if (peripheral == UART7) + #endif + { + #if defined(PIN_SERIAL7_RX) + setRx(PIN_SERIAL7_RX); + #endif + setTx(PIN_SERIAL7_TX); + } else + #endif + #if defined(PIN_SERIAL8_TX) &&\ + (defined(USART8_BASE) || defined(UART8_BASE)) + #if defined(USART8_BASE) + if (peripheral == USART8) + #elif defined(UART8_BASE) + if (peripheral == UART8) + #endif + { + #if defined(PIN_SERIAL8_RX) + setRx(PIN_SERIAL8_RX); + #endif + setTx(PIN_SERIAL8_TX); + } else + #endif + #if defined(PIN_SERIAL9_TX) && defined(UART9_BASE) + if (peripheral == UART9) { + #if defined(PIN_SERIAL9_RX) + setRx(PIN_SERIAL9_RX); + #endif + setTx(PIN_SERIAL9_TX); + } else + #endif + #if defined(PIN_SERIAL10_TX) &&\ + (defined(USART10_BASE) || defined(UART10_BASE)) + #if defined(USART10_BASE) + if (peripheral == USART10) + #elif defined(UART10_BASE) + if (peripheral == UART10) + #endif + { + #if defined(PIN_SERIAL10_RX) + setRx(PIN_SERIAL10_RX); + #endif + setTx(PIN_SERIAL10_TX); + } else + #endif + #if defined(PIN_SERIALLP1_TX) && defined(LPUART1_BASE) + if (peripheral == LPUART1) { + #if defined(PIN_SERIALLP1_RX) + setRx(PIN_SERIALLP1_RX); + #endif + setTx(PIN_SERIALLP1_TX); + } else + #endif + // else get the pins of the first peripheral occurence in PinMap + { + _serial.pin_rx = pinmap_pin(peripheral, PinMap_UART_RX); + _serial.pin_tx = pinmap_pin(peripheral, PinMap_UART_TX); + } + // if (halfDuplex == HALF_DUPLEX_ENABLED) { + // _serial.pin_rx = NC; + // } + init(_serial.pin_rx, _serial.pin_tx); + } + + void WifiSerial::flush() + { + // If we have never written a byte, no need to flush. This special + // case is needed since there is no way to force the TXC (transmit + // complete) bit to 1 during initialization + if (!_written) { + return; + } + + while ((_serial.tx_head != _serial.tx_tail)) { + // nop, the interrupt handler will free up space for us + } + // If we get here, nothing is queued anymore (DRIE is disabled) and + // the hardware finished tranmission (TXC is set). + } + + bool WifiSerial::isHalfDuplex(void) const + { + return _serial.pin_rx == NC; + } + + void WifiSerial::enableHalfDuplexRx(void) + { + if (isHalfDuplex()) { + // In half-duplex mode we have to wait for all TX characters to + // be transmitted before we can receive data. + flush(); + if (!_rx_enabled) { + _rx_enabled = true; + uart_enable_rx(&_serial); + } + } + } + + // Actual interrupt handlers ////////////////////////////////////////////////////////////// + + void WifiSerial::_rx_complete_irq(serial_t *obj) + { + // No Parity error, read byte and store it in the buffer if there is room + unsigned char c; + + if (uart_getc(obj, &c) == 0) { + + WRITE(WIFI_IO1_PIN, HIGH); + + rx_buffer_index_t i = (unsigned int)(obj->rx_head + 1) % WIFI_RX_BUF_SIZE; + + // if we should be storing the received character into the location + // just before the tail (meaning that the head would advance to the + // current location of the tail), we're about to overflow the buffer + // and so we don't write the character or advance the head. + if (i != obj->rx_tail) { + obj->rx_buff[obj->rx_head] = c; + obj->rx_head = i; + } + } + } + + // Actual interrupt handlers ////////////////////////////////////////////////////////////// + + int WifiSerial::_tx_complete_irq(serial_t *obj) + { + // If interrupts are enabled, there must be more data in the output + // buffer. Send the next byte + obj->tx_tail = (obj->tx_tail + 1) % WIFI_TX_BUF_SIZE; + + if (obj->tx_head == obj->tx_tail) { + return -1; + } + + return 0; + } + + void WifiSerial::begin(unsigned long baud) { begin(baud, SERIAL_8N1); } + + void WifiSerial::begin(unsigned long baud, byte config) { + uint32_t databits = 0; + uint32_t stopbits = 0; + uint32_t parity = 0; + + _baud = baud; + _config = config; + + // Manage databits + switch (config & 0x07) { + case 0x02: + databits = 6; + break; + case 0x04: + databits = 7; + break; + case 0x06: + databits = 8; + break; + default: + databits = 0; + break; + } + + if ((config & 0x30) == 0x30) { + parity = UART_PARITY_ODD; + databits++; + } else if ((config & 0x20) == 0x20) { + parity = UART_PARITY_EVEN; + databits++; + } else { + parity = UART_PARITY_NONE; + } + + if ((config & 0x08) == 0x08) { + stopbits = UART_STOPBITS_2; + } else { + stopbits = UART_STOPBITS_1; + } + + switch (databits) { + #ifdef UART_WORDLENGTH_7B + case 7: + databits = UART_WORDLENGTH_7B; + break; + #endif + case 8: + databits = UART_WORDLENGTH_8B; + break; + case 9: + databits = UART_WORDLENGTH_9B; + break; + default: + case 0: + Error_Handler(); + break; + } + + uart_init(&_serial, (uint32_t)baud, databits, parity, stopbits); + enableHalfDuplexRx(); + if (baud == WIFI_BAUDRATE) uart_attach_rx_callback(&_serial, _rx_complete_irq); + else { + USART1->CR1 |= (USART_CR1_RE);// don't change the word length etc, and 'or' in the patten not overwrite |USART_CR1_M_8N1); + } + } + + void WifiSerial::end(void) + { + // wait for transmission of outgoing data + flush(); + + uart_deinit(&_serial); + + // clear any received data + _serial.rx_head = _serial.rx_tail; + } + + int WifiSerial::available(void) { + return ((unsigned int)(WIFI_RX_BUF_SIZE + _serial.rx_head - _serial.rx_tail)) % WIFI_RX_BUF_SIZE; + } + + // + // I/O + // + int WifiSerial::read(void) + { + enableHalfDuplexRx(); + // if the head isn't ahead of the tail, we don't have any characters + if (_serial.rx_head == _serial.rx_tail) { + return -1; + } else { + unsigned char c = _serial.rx_buff[_serial.rx_tail]; + _serial.rx_tail = (rx_buffer_index_t)(_serial.rx_tail + 1) % WIFI_RX_BUF_SIZE; + return c; + } + } + + int WifiSerial::write(uint8_t c) + { + _written = true; + if (isHalfDuplex()) { + if (_rx_enabled) { + _rx_enabled = false; + uart_enable_tx(&_serial); + } + } + + tx_buffer_index_t i = (_serial.tx_head + 1) % WIFI_TX_BUF_SIZE; + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + while (i == _serial.tx_tail) { + // nop, the interrupt handler will free up space for us + } + + _serial.tx_buff[_serial.tx_head] = c; + _serial.tx_head = i; + + if (!serial_tx_active(&_serial)) { + uart_attach_tx_callback(&_serial, _tx_complete_irq); + } + + return 1; + } +#endif // __STM32F1__ +#endif // MKS_WIFI_MODULE +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.h b/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.h new file mode 100644 index 0000000..cd11d6b --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/wifiSerial.h @@ -0,0 +1,145 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#include "tft_lvgl_configuration.h" + +#if ENABLED(MKS_WIFI_MODULE) + +#ifdef SERIAL_PORT_2 + #error "SERIAL_PORT_2 must be disabled with TFT_LVGL_UI* and MKS_WIFI_MODULE." +#endif + +#define WIFI_BAUDRATE 115200 +#define WIFI_UPLOAD_BAUDRATE 1958400 +#define USART_SAFE_INSERT + +#define WIFI_RX_BUF_SIZE (1024) +#define WIFI_TX_BUF_SIZE (64) + +#ifdef __STM32F1__ + + #include <libmaple/libmaple_types.h> + #include <libmaple/usart.h> + #include <libmaple/libmaple.h> + #include <libmaple/gpio.h> + #include <libmaple/timer.h> + #include <libmaple/ring_buffer.h> + + #define DEFINE_WFSERIAL(name, n)\ + WifiSerial name(USART##n, \ + BOARD_USART##n##_TX_PIN, \ + BOARD_USART##n##_RX_PIN) + + class WifiSerial { + public: + uint8 wifiRxBuf[WIFI_RX_BUF_SIZE]; + + public: + WifiSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin); + + /* Set up/tear down */ + void begin(uint32 baud); + void begin(uint32 baud,uint8_t config); + void end(); + int available(void); + int read(void); + int write(uint8_t); + inline void wifi_usart_irq(usart_reg_map *regs) { + /* Handling RXNEIE and TXEIE interrupts. + * RXNE signifies availability of a byte in DR. + * + * See table 198 (sec 27.4, p809) in STM document RM0008 rev 15. + * We enable RXNEIE. + */ + if ((regs->CR1 & USART_CR1_RXNEIE) && (regs->SR & USART_SR_RXNE)) { + #ifdef USART_SAFE_INSERT + /* If the buffer is full and the user defines USART_SAFE_INSERT, + * ignore new bytes. */ + rb_safe_insert(this->usart_device->rb, (uint8)regs->DR); + #else + /* By default, push bytes around in the ring buffer. */ + rb_push_insert(this->usart_device->rb, (uint8)regs->DR); + #endif + } + /* TXE signifies readiness to send a byte to DR. */ + if ((regs->CR1 & USART_CR1_TXEIE) && (regs->SR & USART_SR_TXE)) { + if (!rb_is_empty(this->usart_device->wb)) + regs->DR=rb_remove(this->usart_device->wb); + else + regs->CR1 &= ~((uint32)USART_CR1_TXEIE); // disable TXEIE + } + } + int wifi_rb_is_full(void); + struct usart_dev *usart_device; + private: + uint8 tx_pin; + uint8 rx_pin; + }; + extern WifiSerial WifiSerial1; + #define WIFISERIAL WifiSerial1 +#else + + #include <inttypes.h> + #include "Stream.h" + #include "uart.h" + + class WifiSerial { + protected: + // Has any byte been written to the UART since begin() + bool _written; + serial_t _serial; + public: + uint8_t wifiRxBuf[WIFI_RX_BUF_SIZE]; + uint8_t wifiTxBuf[WIFI_TX_BUF_SIZE]; + WifiSerial(void *peripheral); + + /* Set up/tear down */ + void begin(uint32_t baud); + void begin(uint32_t baud,uint8_t config); + void end(); + int available(void); + int read(void); + int write(uint8_t); + + // Interrupt handlers + static int _tx_complete_irq(serial_t *obj); + static void _rx_complete_irq(serial_t *obj); + + void flush(void); + bool isHalfDuplex(void) const; + void enableHalfDuplexRx(void); + + private: + void setRx(uint32_t _rx); + void setTx(uint32_t _tx); + void setRx(PinName _rx); + void setTx(PinName _tx); + void init(PinName _rx, PinName _tx); + bool _rx_enabled; + uint8_t _config; + unsigned long _baud; + }; + extern WifiSerial WifiSerial1; + #define WIFISERIAL WifiSerial1 +#endif // __STM32F1__ +#endif // MKS_WIFI_MODULE diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp new file mode 100644 index 0000000..0e4163c --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.cpp @@ -0,0 +1,2231 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if HAS_TFT_LVGL_UI + +#include "draw_ui.h" +#include "wifi_module.h" +#include "wifi_upload.h" +#include "SPI_TFT.h" + +#if ENABLED(MKS_WIFI_MODULE) + +#include "../../../../MarlinCore.h" +#include "../../../../module/temperature.h" +#include "../../../../gcode/queue.h" +#include "../../../../gcode/gcode.h" +#include "../../../../lcd/marlinui.h" +#include "../../../../sd/cardreader.h" +#include "../../../../module/planner.h" +#include "../../../../module/servo.h" +#include "../../../../module/probe.h" +#if ENABLED(POWER_LOSS_RECOVERY) + #include "../../../../feature/powerloss.h" +#endif +#if ENABLED(PARK_HEAD_ON_PAUSE) + #include "../../../../feature/pause.h" +#endif + +#define WIFI_SET() WRITE(WIFI_RESET_PIN, HIGH); +#define WIFI_RESET() WRITE(WIFI_RESET_PIN, LOW); +#define WIFI_IO1_SET() WRITE(WIFI_IO1_PIN, HIGH); +#define WIFI_IO1_RESET() WRITE(WIFI_IO1_PIN, LOW); + +extern uint8_t Explore_Disk (char* path , uint8_t recu_level); + +extern uint8_t commands_in_queue; +extern uint8_t sel_id; +extern unsigned int getTickDiff(unsigned int curTick, unsigned int lastTick); + +SZ_USART_FIFO WifiRxFifo; + +#define WAIT_ESP_TRANS_TIMEOUT_TICK 10500 + +int cfg_cloud_flag = 0; + +extern PRINT_TIME print_time; + +char wifi_firm_ver[20] = { 0 }; +WIFI_GCODE_BUFFER espGcodeFifo; +extern uint8_t pause_resum; + +uint8_t wifi_connect_flg = 0; +extern volatile uint8_t get_temp_flag; + +#define WIFI_MODE 2 +#define WIFI_AP_MODE 3 + +int upload_result = 0; + +uint32_t upload_time = 0; +uint32_t upload_size = 0; + +volatile WIFI_STATE wifi_link_state; +WIFI_PARA wifiPara; +IP_PARA ipPara; +CLOUD_PARA cloud_para; + +char wifi_check_time = 0; + +extern uint8_t gCurDir[100]; + +extern uint32_t wifi_loop_cycle; + +volatile TRANSFER_STATE esp_state; + +uint8_t left_to_send = 0; +uint8_t left_to_save[96] = { 0 }; + +volatile WIFI_DMA_RCV_FIFO wifiDmaRcvFifo; + +volatile WIFI_TRANS_ERROR wifiTransError; + +static bool need_ok_later = false; + +extern volatile WIFI_STATE wifi_link_state; +extern WIFI_PARA wifiPara; +extern IP_PARA ipPara; +extern CLOUD_PARA cloud_para; + +extern bool once_flag, flash_preview_begin, default_preview_flg, gcode_preview_over; +extern char flash_dma_mode; + +uint32_t getWifiTick() { + return millis(); +} + +uint32_t getWifiTickDiff(int32_t lastTick, int32_t curTick) { + if (lastTick <= curTick) + return (curTick - lastTick) * TICK_CYCLE; + else + return (0xFFFFFFFF - lastTick + curTick) * TICK_CYCLE; +} + +void wifi_delay(int n) { + uint32_t begin = getWifiTick(); + uint32_t end = begin; + while (getWifiTickDiff(begin, end) < (uint32_t)n) { + end = getWifiTick(); + } +} + +void wifi_reset() { + uint32_t start, now; + start = getWifiTick(); + now = start; + WIFI_RESET(); + while (getWifiTickDiff(start, now) < 500) + now = getWifiTick(); + + WIFI_SET(); +} + +void mount_file_sys(uint8_t disk_type) { + if (disk_type == FILE_SYS_SD) { + TERN_(SDSUPPORT, card.mount()); + } + else if (disk_type == FILE_SYS_USB) { + } +} + +static bool longName2DosName(const char *longName, uint8_t *dosName) { + uint8_t i = FILENAME_LENGTH; + while (i) + dosName[--i] = '\0'; + while (*longName) { + uint8_t c = *longName++; + if (c == '.') { // For a dot... + if (i == 0) { + return false; + } + else { + strcat((char *)dosName, ".GCO"); + return dosName[0] != '\0'; + } + } + else { + // Fail for illegal characters + PGM_P p = PSTR("|<>^+=?/[];,*\"\\"); + while (uint8_t b = pgm_read_byte(p++)) + if (b == c) + return false; + if (c < 0x21 || c == 0x7F) + return false; // Check size, non-printable characters + dosName[i++] = (c < 'a' || c > 'z') ? (c) : (c + ('A' - 'a')); // Uppercase required for 8.3 name + } + if (i >= 5) { + strcat((char *)dosName, "~1.GCO"); + return dosName[0] != '\0'; + } + } + return dosName[0] != '\0'; // Return true if any name was set +} + +#ifdef __STM32F1__ + + #include <libmaple/timer.h> + #include <libmaple/util.h> + #include <libmaple/rcc.h> + + #include <boards.h> + #include <wirish.h> + + #include <libmaple/dma.h> + #include <libmaple/bitband.h> + + #include <libmaple/libmaple.h> + #include <libmaple/gpio.h> + #include <libmaple/usart.h> + #include <libmaple/ring_buffer.h> + + void exchangeFlashMode(char dmaMode) { + if (flash_dma_mode != dmaMode) { + flash_dma_mode = dmaMode; + if (flash_dma_mode == 1) { + } + else { + dma_disable(DMA1, DMA_CH5); + dma_clear_isr_bits(DMA1, DMA_CH4); + } + } + } + + static int storeRcvData(volatile uint8_t *bufToCpy, int32_t len) { + unsigned char tmpW = wifiDmaRcvFifo.write_cur; + if (len > UDISKBUFLEN) return 0; + if (wifiDmaRcvFifo.state[tmpW] == udisk_buf_empty) { + memcpy((unsigned char *) wifiDmaRcvFifo.bufferAddr[tmpW], (uint8_t *)bufToCpy, len); + wifiDmaRcvFifo.state[tmpW] = udisk_buf_full; + wifiDmaRcvFifo.write_cur = (tmpW + 1) % TRANS_RCV_FIFO_BLOCK_NUM; + return 1; + } + return 0; + } + + static void esp_dma_pre() { + dma_channel_reg_map *channel_regs = dma_tube_regs(DMA1, DMA_CH5); + + CBI32(channel_regs->CCR, 0); + channel_regs->CMAR = (uint32_t)WIFISERIAL.usart_device->rb->buf; + channel_regs->CNDTR = 0x0000; + channel_regs->CNDTR = UART_RX_BUFFER_SIZE; + DMA1->regs->IFCR = 0xF0000; + SBI32(channel_regs->CCR, 0); + } + + static void dma_ch5_irq_handle() { + uint8 status_bits = dma_get_isr_bits(DMA1, DMA_CH5); + dma_clear_isr_bits(DMA1, DMA_CH5); + if (status_bits & 0x8) { + // DMA transmit Error + } + else if (status_bits & 0x2) { + // DMA transmit complete + if (esp_state == TRANSFER_IDLE) + esp_state = TRANSFERING; + + if (storeRcvData(WIFISERIAL.usart_device->rb->buf, UART_RX_BUFFER_SIZE)) { + esp_dma_pre(); + if (wifiTransError.flag != 0x1) + WIFI_IO1_RESET(); + } + else { + WIFI_IO1_SET(); + esp_state = TRANSFER_STORE; + } + } + else if (status_bits & 0x4) { + // DMA transmit half + WIFI_IO1_SET(); + } + } + static void wifi_usart_dma_init() { + dma_init(DMA1); + uint32_t flags = ( DMA_MINC_MODE | DMA_TRNS_CMPLT | DMA_HALF_TRNS | DMA_TRNS_ERR); + dma_xfer_size dma_bit_size = DMA_SIZE_8BITS; + dma_setup_transfer(DMA1, DMA_CH5, &USART1_BASE->DR, dma_bit_size, + (volatile void*)WIFISERIAL.usart_device->rb->buf, dma_bit_size, flags);// Transmit buffer DMA + dma_set_priority(DMA1, DMA_CH5, DMA_PRIORITY_LOW); + dma_attach_interrupt(DMA1, DMA_CH5, &dma_ch5_irq_handle); + + dma_clear_isr_bits(DMA1, DMA_CH5); + dma_set_num_transfers(DMA1, DMA_CH5, UART_RX_BUFFER_SIZE); + + bb_peri_set_bit(&USART1_BASE->CR3, USART_CR3_DMAR_BIT, 1); + dma_enable(DMA1, DMA_CH5); // enable transmit + + for (uint8_t i = 0; i < TRANS_RCV_FIFO_BLOCK_NUM; i++) { + wifiDmaRcvFifo.bufferAddr[i] = &bmp_public_buf[1024 * i]; + wifiDmaRcvFifo.state[i] = udisk_buf_empty; + } + + memset(wifiDmaRcvFifo.bufferAddr[0], 0, 1024 * TRANS_RCV_FIFO_BLOCK_NUM); + wifiDmaRcvFifo.read_cur = 0; + wifiDmaRcvFifo.write_cur = 0; + } + + void esp_port_begin(uint8_t interrupt) { + WifiRxFifo.uart_read_point = 0; + WifiRxFifo.uart_write_point = 0; + if (interrupt) { + #if ENABLED(MKS_WIFI_MODULE) + WIFISERIAL.end(); + for (uint16_t i = 0; i < 65535; i++) { /*nada*/ } + WIFISERIAL.begin(WIFI_BAUDRATE); + uint32_t serial_connect_timeout = millis() + 1000UL; + while (PENDING(millis(), serial_connect_timeout)) { /*nada*/ } + #endif + } + else { + #if ENABLED(MKS_WIFI_MODULE) + WIFISERIAL.end(); + WIFISERIAL.usart_device->regs->CR1 &= ~USART_CR1_RXNEIE; + WIFISERIAL.begin(WIFI_UPLOAD_BAUDRATE); + wifi_usart_dma_init(); + #endif + } + } +#else + + DMA_HandleTypeDef wifiUsartDMArx; + + void exchangeFlashMode(char dmaMode) { + if (flash_dma_mode != dmaMode) { + flash_dma_mode = dmaMode; + if (flash_dma_mode == 1) { + } + else { + } + } + } + + #ifdef STM32F1xx + + HAL_StatusTypeDef HAL_DMA_PollForTransferCustomize(DMA_HandleTypeDef *hdma, uint32_t CompleteLevel, uint32_t Timeout) + { + uint32_t temp; + uint32_t tickstart = 0U; + + if(HAL_DMA_STATE_BUSY != hdma->State) + { + /* no transfer ongoing */ + hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER; + __HAL_UNLOCK(hdma); + return HAL_ERROR; + } + + /* Polling mode not supported in circular mode */ + if (RESET != (hdma->Instance->CCR & DMA_CCR_CIRC)) + { + hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED; + return HAL_ERROR; + } + + /* Get the level transfer complete flag */ + if(CompleteLevel == HAL_DMA_FULL_TRANSFER) + { + /* Transfer Complete flag */ + temp = __HAL_DMA_GET_TC_FLAG_INDEX(hdma); + } + else + { + /* Half Transfer Complete flag */ + temp = __HAL_DMA_GET_HT_FLAG_INDEX(hdma); + } + + /* Get tick */ + tickstart = HAL_GetTick(); + + while(__HAL_DMA_GET_FLAG(hdma, temp) == RESET) + { + if((__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma)) != RESET)) + { + /* Clear the half transfer complete flag */ + __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma)); + WIFI_IO1_SET(); + } + + if((__HAL_DMA_GET_FLAG(hdma, __HAL_DMA_GET_TE_FLAG_INDEX(hdma)) != RESET)) + { + /* When a DMA transfer error occurs */ + /* A hardware clear of its EN bits is performed */ + /* Clear all flags */ + hdma->DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma->ChannelIndex); + + /* Update error code */ + SET_BIT(hdma->ErrorCode, HAL_DMA_ERROR_TE); + + /* Change the DMA state */ + hdma->State= HAL_DMA_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hdma); + + return HAL_ERROR; + } + /* Check for the Timeout */ + if(Timeout != HAL_MAX_DELAY) + { + if((Timeout == 0U) || ((HAL_GetTick() - tickstart) > Timeout)) + { + /* Update error code */ + SET_BIT(hdma->ErrorCode, HAL_DMA_ERROR_TIMEOUT); + + /* Change the DMA state */ + hdma->State = HAL_DMA_STATE_READY; + + /* Process Unlocked */ + __HAL_UNLOCK(hdma); + + return HAL_ERROR; + } + } + } + + if(CompleteLevel == HAL_DMA_FULL_TRANSFER) + { + /* Clear the transfer complete flag */ + __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma)); + + /* The selected Channelx EN bit is cleared (DMA is disabled and + all transfers are complete) */ + hdma->State = HAL_DMA_STATE_READY; + } + else + { + /* Clear the half transfer complete flag */ + __HAL_DMA_CLEAR_FLAG(hdma, __HAL_DMA_GET_HT_FLAG_INDEX(hdma)); + } + + /* Process unlocked */ + __HAL_UNLOCK(hdma); + + return HAL_OK; + } + #else + + typedef struct + { + __IO uint32_t ISR; /*!< DMA interrupt status register */ + __IO uint32_t Reserved0; + __IO uint32_t IFCR; /*!< DMA interrupt flag clear register */ + } MYDMA_Base_Registers; + + HAL_StatusTypeDef HAL_DMA_PollForTransferCustomize(DMA_HandleTypeDef *hdma, HAL_DMA_LevelCompleteTypeDef CompleteLevel, uint32_t Timeout) + { + HAL_StatusTypeDef status = HAL_OK; + uint32_t mask_cpltlevel; + uint32_t tickstart = HAL_GetTick(); + uint32_t tmpisr; + + /* calculate DMA base and stream number */ + MYDMA_Base_Registers *regs; + + if(HAL_DMA_STATE_BUSY != hdma->State) + { + /* No transfer ongoing */ + hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER; + __HAL_UNLOCK(hdma); + return HAL_ERROR; + } + + /* Polling mode not supported in circular mode and double buffering mode */ + if ((hdma->Instance->CR & DMA_SxCR_CIRC) != RESET) + { + hdma->ErrorCode = HAL_DMA_ERROR_NOT_SUPPORTED; + return HAL_ERROR; + } + + /* Get the level transfer complete flag */ + if(CompleteLevel == HAL_DMA_FULL_TRANSFER) + { + /* Transfer Complete flag */ + mask_cpltlevel = DMA_FLAG_TCIF0_4 << hdma->StreamIndex; + } + else + { + /* Half Transfer Complete flag */ + mask_cpltlevel = DMA_FLAG_HTIF0_4 << hdma->StreamIndex; + } + + regs = (MYDMA_Base_Registers *)hdma->StreamBaseAddress; + tmpisr = regs->ISR; + + while(((tmpisr & mask_cpltlevel) == RESET) && ((hdma->ErrorCode & HAL_DMA_ERROR_TE) == RESET)) + { + /* Check for the Timeout (Not applicable in circular mode)*/ + if(Timeout != HAL_MAX_DELAY) + { + if((Timeout == 0U)||((HAL_GetTick() - tickstart ) > Timeout)) + { + /* Update error code */ + hdma->ErrorCode = HAL_DMA_ERROR_TIMEOUT; + + /* Process Unlocked */ + __HAL_UNLOCK(hdma); + + /* Change the DMA state */ + hdma->State = HAL_DMA_STATE_READY; + + return HAL_TIMEOUT; + } + } + + /* Get the ISR register value */ + tmpisr = regs->ISR; + + if((tmpisr & (DMA_FLAG_HTIF0_4 << hdma->StreamIndex)) != RESET) + { + /* Clear the Direct Mode error flag */ + regs->IFCR = DMA_FLAG_HTIF0_4 << hdma->StreamIndex; + WIFI_IO1_SET(); + } + + if((tmpisr & (DMA_FLAG_TEIF0_4 << hdma->StreamIndex)) != RESET) + { + /* Update error code */ + hdma->ErrorCode |= HAL_DMA_ERROR_TE; + + /* Clear the transfer error flag */ + regs->IFCR = DMA_FLAG_TEIF0_4 << hdma->StreamIndex; + } + + if((tmpisr & (DMA_FLAG_FEIF0_4 << hdma->StreamIndex)) != RESET) + { + /* Update error code */ + hdma->ErrorCode |= HAL_DMA_ERROR_FE; + + /* Clear the FIFO error flag */ + regs->IFCR = DMA_FLAG_FEIF0_4 << hdma->StreamIndex; + } + + if((tmpisr & (DMA_FLAG_DMEIF0_4 << hdma->StreamIndex)) != RESET) + { + /* Update error code */ + hdma->ErrorCode |= HAL_DMA_ERROR_DME; + + /* Clear the Direct Mode error flag */ + regs->IFCR = DMA_FLAG_DMEIF0_4 << hdma->StreamIndex; + } + } + + if(hdma->ErrorCode != HAL_DMA_ERROR_NONE) + { + if((hdma->ErrorCode & HAL_DMA_ERROR_TE) != RESET) + { + HAL_DMA_Abort(hdma); + + /* Clear the half transfer and transfer complete flags */ + regs->IFCR = (DMA_FLAG_HTIF0_4 | DMA_FLAG_TCIF0_4) << hdma->StreamIndex; + + /* Process Unlocked */ + __HAL_UNLOCK(hdma); + + /* Change the DMA state */ + hdma->State= HAL_DMA_STATE_READY; + + return HAL_ERROR; + } + } + + /* Get the level transfer complete flag */ + if(CompleteLevel == HAL_DMA_FULL_TRANSFER) + { + /* Clear the half transfer and transfer complete flags */ + regs->IFCR = (DMA_FLAG_HTIF0_4 | DMA_FLAG_TCIF0_4) << hdma->StreamIndex; + + /* Process Unlocked */ + __HAL_UNLOCK(hdma); + + hdma->State = HAL_DMA_STATE_READY; + } + else + { + /* Clear the half transfer and transfer complete flags */ + regs->IFCR = (DMA_FLAG_HTIF0_4) << hdma->StreamIndex; + } + + return status; + } + #endif + + static void dmaTransmitBegin() { + wifiUsartDMArx.Init.MemInc = DMA_MINC_ENABLE; + if (HAL_DMA_Init((DMA_HandleTypeDef *)&wifiUsartDMArx) != HAL_OK) { + Error_Handler(); + } + if (HAL_DMA_Start(&wifiUsartDMArx, (uint32_t)&(USART1->DR), (uint32_t)WIFISERIAL.wifiRxBuf, UART_RX_BUFFER_SIZE)) { + Error_Handler(); + } + USART1->CR1 |= USART_CR1_UE; + + SET_BIT(USART1->CR3, USART_CR3_DMAR); + WIFI_IO1_RESET(); + } + + static int storeRcvData(volatile uint8_t *bufToCpy, int32_t len) { + unsigned char tmpW = wifiDmaRcvFifo.write_cur; + + if (len > UDISKBUFLEN) return 0; + + if (wifiDmaRcvFifo.state[tmpW] == udisk_buf_empty) { + const int timeOut = 2000; //millisecond + dmaTransmitBegin(); + if(HAL_DMA_PollForTransferCustomize(&wifiUsartDMArx, HAL_DMA_FULL_TRANSFER, timeOut) == HAL_OK) { + memcpy((unsigned char *) wifiDmaRcvFifo.bufferAddr[tmpW], (uint8_t *)bufToCpy, len); + wifiDmaRcvFifo.state[tmpW] = udisk_buf_full; + wifiDmaRcvFifo.write_cur = (tmpW + 1) % TRANS_RCV_FIFO_BLOCK_NUM; + return 1; + } + } + return 0; + } + + static void wifi_usart_dma_init() { + #ifdef STM32F1xx + __HAL_RCC_DMA1_CLK_ENABLE(); + wifiUsartDMArx.Instance = DMA1_Channel5; + #else + __HAL_RCC_DMA2_CLK_ENABLE(); + wifiUsartDMArx.Instance = DMA2_Stream2; + wifiUsartDMArx.Init.Channel = DMA_CHANNEL_4; + #endif + wifiUsartDMArx.Init.Direction = DMA_PERIPH_TO_MEMORY; + wifiUsartDMArx.Init.PeriphInc = DMA_PINC_DISABLE; + wifiUsartDMArx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + wifiUsartDMArx.Init.MemDataAlignment = DMA_PDATAALIGN_BYTE; + wifiUsartDMArx.Init.Mode = DMA_NORMAL; + #ifdef STM32F4xx + wifiUsartDMArx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + #endif + wifiUsartDMArx.Init.MemInc = DMA_MINC_ENABLE; + if (HAL_DMA_Init((DMA_HandleTypeDef *)&wifiUsartDMArx) != HAL_OK) { + Error_Handler(); + } + if (HAL_DMA_Start(&wifiUsartDMArx, (uint32_t)&(USART1->DR), (uint32_t)WIFISERIAL.wifiRxBuf, UART_RX_BUFFER_SIZE)) { + Error_Handler(); + } + USART1->CR1 |= USART_CR1_UE; + + SET_BIT(USART1->CR3, USART_CR3_DMAR); /* Enable Rx DMA Request */ + + for (uint8_t i = 0; i < TRANS_RCV_FIFO_BLOCK_NUM; i++) { + wifiDmaRcvFifo.bufferAddr[i] = &bmp_public_buf[1024 * i]; + wifiDmaRcvFifo.state[i] = udisk_buf_empty; + } + + memset(wifiDmaRcvFifo.bufferAddr[0], 0, 1024 * TRANS_RCV_FIFO_BLOCK_NUM); + wifiDmaRcvFifo.read_cur = 0; + wifiDmaRcvFifo.write_cur = 0; + } + + + void esp_port_begin(uint8_t interrupt) { + WifiRxFifo.uart_read_point = 0; + WifiRxFifo.uart_write_point = 0; + + if (interrupt) { + #if ENABLED(MKS_WIFI_MODULE) + WIFISERIAL.end(); + for (uint16_t i = 0; i < 65535; i++) { /*nada*/ } + WIFISERIAL.begin(WIFI_BAUDRATE); + uint32_t serial_connect_timeout = millis() + 1000UL; + while (PENDING(millis(), serial_connect_timeout)) { /*nada*/ } + #endif + } + else { + #if ENABLED(MKS_WIFI_MODULE) + WIFISERIAL.end(); + USART1->CR1 &= ~USART_CR1_RXNEIE; + WIFISERIAL.begin(WIFI_UPLOAD_BAUDRATE); + wifi_usart_dma_init(); + #endif + } + } +#endif // + +#if ENABLED(MKS_WIFI_MODULE) + + int raw_send_to_wifi(uint8_t *buf, int len) { + if (buf == 0 || len <= 0) return 0; + for (int i = 0; i < len; i++) + WIFISERIAL.write(*(buf + i)); + return len; + } + +#endif + +void wifi_ret_ack() {} + +uint8_t buf_to_wifi[256]; +int index_to_wifi = 0; +int package_to_wifi(WIFI_RET_TYPE type, uint8_t *buf, int len) { + uint8_t wifi_ret_head = 0xA5; + uint8_t wifi_ret_tail = 0xFC; + + if (type == WIFI_PARA_SET) { + int data_offset = 4; + int apLen = strlen((const char *)uiCfg.wifi_name); + int keyLen = strlen((const char *)uiCfg.wifi_key); + + ZERO(buf_to_wifi); + index_to_wifi = 0; + + buf_to_wifi[data_offset] = gCfgItems.wifi_mode_sel; + buf_to_wifi[data_offset + 1] = apLen; + memcpy(&buf_to_wifi[data_offset + 2], (const char *)uiCfg.wifi_name, apLen); + buf_to_wifi[data_offset + apLen + 2] = keyLen; + memcpy(&buf_to_wifi[data_offset + apLen + 3], (const char *)uiCfg.wifi_key, keyLen); + buf_to_wifi[data_offset + apLen + keyLen + 3] = wifi_ret_tail; + + index_to_wifi = apLen + keyLen + 3; + + buf_to_wifi[0] = wifi_ret_head; + buf_to_wifi[1] = type; + buf_to_wifi[2] = index_to_wifi & 0xFF; + buf_to_wifi[3] = (index_to_wifi >> 8) & 0xFF; + + raw_send_to_wifi(buf_to_wifi, 5 + index_to_wifi); + + ZERO(buf_to_wifi); + index_to_wifi = 0; + } + else if (type == WIFI_TRANS_INF) { + if (len > (int)(sizeof(buf_to_wifi) - index_to_wifi - 5)) { + ZERO(buf_to_wifi); + index_to_wifi = 0; + return 0; + } + + if (len > 0) { + memcpy(&buf_to_wifi[4 + index_to_wifi], buf, len); + index_to_wifi += len; + + if (index_to_wifi < 1) + return 0; + + if (buf_to_wifi[index_to_wifi + 3] == '\n') { + // mask "wait" "busy" "X:" + if (((buf_to_wifi[4] == 'w') && (buf_to_wifi[5] == 'a') && (buf_to_wifi[6] == 'i') && (buf_to_wifi[7] == 't') ) + || ((buf_to_wifi[4] == 'b') && (buf_to_wifi[5] == 'u') && (buf_to_wifi[6] == 's') && (buf_to_wifi[7] == 'y') ) + || ((buf_to_wifi[4] == 'X') && (buf_to_wifi[5] == ':') ) + ) { + ZERO(buf_to_wifi); + index_to_wifi = 0; + return 0; + } + + buf_to_wifi[0] = wifi_ret_head; + buf_to_wifi[1] = type; + buf_to_wifi[2] = index_to_wifi & 0xFF; + buf_to_wifi[3] = (index_to_wifi >> 8) & 0xFF; + buf_to_wifi[4 + index_to_wifi] = wifi_ret_tail; + + raw_send_to_wifi(buf_to_wifi, 5 + index_to_wifi); + + ZERO(buf_to_wifi); + index_to_wifi = 0; + } + } + } + else if (type == WIFI_EXCEP_INF) { + ZERO(buf_to_wifi); + + buf_to_wifi[0] = wifi_ret_head; + buf_to_wifi[1] = type; + buf_to_wifi[2] = 1; + buf_to_wifi[3] = 0; + buf_to_wifi[4] = *buf; + buf_to_wifi[5] = wifi_ret_tail; + + raw_send_to_wifi(buf_to_wifi, 6); + + ZERO(buf_to_wifi); + index_to_wifi = 0; + } + else if (type == WIFI_CLOUD_CFG) { + int data_offset = 4; + int urlLen = strlen((const char *)uiCfg.cloud_hostUrl); + + ZERO(buf_to_wifi); + index_to_wifi = 0; + + buf_to_wifi[data_offset] = gCfgItems.cloud_enable ? 0x0A : 0x05; + buf_to_wifi[data_offset + 1] = urlLen; + memcpy(&buf_to_wifi[data_offset + 2], (const char *)uiCfg.cloud_hostUrl, urlLen); + buf_to_wifi[data_offset + urlLen + 2] = uiCfg.cloud_port & 0xFF; + buf_to_wifi[data_offset + urlLen + 3] = (uiCfg.cloud_port >> 8) & 0xFF; + buf_to_wifi[data_offset + urlLen + 4] = wifi_ret_tail; + + index_to_wifi = urlLen + 4; + + buf_to_wifi[0] = wifi_ret_head; + buf_to_wifi[1] = type; + buf_to_wifi[2] = index_to_wifi & 0xFF; + buf_to_wifi[3] = (index_to_wifi >> 8) & 0xFF; + + raw_send_to_wifi(buf_to_wifi, 5 + index_to_wifi); + + ZERO(buf_to_wifi); + index_to_wifi = 0; + } + else if (type == WIFI_CLOUD_UNBIND) { + ZERO(buf_to_wifi); + + buf_to_wifi[0] = wifi_ret_head; + buf_to_wifi[1] = type; + buf_to_wifi[2] = 0; + buf_to_wifi[3] = 0; + buf_to_wifi[4] = wifi_ret_tail; + + raw_send_to_wifi(buf_to_wifi, 5); + + ZERO(buf_to_wifi); + index_to_wifi = 0; + } + return 1; +} + + +#define SEND_OK_TO_WIFI send_to_wifi((uint8_t *)"ok\r\n", strlen("ok\r\n")) +int send_to_wifi(uint8_t *buf, int len) { return package_to_wifi(WIFI_TRANS_INF, buf, len); } + +void set_cur_file_sys(int fileType) { gCfgItems.fileSysType = fileType; } + +void get_file_list(char *path) { + if (!path) return; + + if (gCfgItems.fileSysType == FILE_SYS_SD) { + TERN_(SDSUPPORT, card.mount()); + } + else if (gCfgItems.fileSysType == FILE_SYS_USB) { + // udisk + } + Explore_Disk(path, 0); +} + +char wait_ip_back_flag = 0; + +typedef struct { + int write_index; + uint8_t saveFileName[30]; + uint8_t fileTransfer; + uint32_t fileLen; + uint32_t tick_begin; + uint32_t tick_end; +} FILE_WRITER; + +FILE_WRITER file_writer; + +int32_t lastFragment = 0; + +char saveFilePath[50]; + +static SdFile upload_file, *upload_curDir; +static filepos_t pos; + +int write_to_file(char *buf, int len) { + int i; + int res = 0; + + for (i = 0; i < len; i++) { + public_buf[file_writer.write_index++] = buf[i]; + if (file_writer.write_index >= 512) { + res = upload_file.write(public_buf, file_writer.write_index); + + if (res == -1) { + upload_file.close(); + const char * const fname = card.diveToFile(true, upload_curDir, saveFilePath); + + if (upload_file.open(upload_curDir, fname, O_WRITE)) { + upload_file.setpos(&pos); + res = upload_file.write(public_buf, file_writer.write_index); + } + } + if (res == -1) { + return -1; + } + upload_file.getpos(&pos); + file_writer.write_index = 0; + } + } + + if (res == -1) { + memset(public_buf, 0, sizeof(public_buf)); + file_writer.write_index = 0; + return -1; + } + + return 0; +} + +#define ESP_PROTOC_HEAD (uint8_t)0xA5 +#define ESP_PROTOC_TAIL (uint8_t)0xFC + +#define ESP_TYPE_NET (uint8_t)0x0 +#define ESP_TYPE_GCODE (uint8_t)0x1 +#define ESP_TYPE_FILE_FIRST (uint8_t)0x2 +#define ESP_TYPE_FILE_FRAGMENT (uint8_t)0x3 + +#define ESP_TYPE_WIFI_LIST (uint8_t)0x4 + +uint8_t esp_msg_buf[UART_RX_BUFFER_SIZE] = { 0 }; +uint16_t esp_msg_index = 0; + +typedef struct { + uint8_t head; + uint8_t type; + uint16_t dataLen; + uint8_t *data; + uint8_t tail; +} ESP_PROTOC_FRAME; + + +static int cut_msg_head(uint8_t *msg, uint16_t msgLen, uint16_t cutLen) { + if (msgLen < cutLen) return 0; + + else if (msgLen == cutLen) { + memset(msg, 0, msgLen); + return 0; + } + + for (int i = 0; i < (msgLen - cutLen); i++) + msg[i] = msg[cutLen + i]; + + memset(&msg[msgLen - cutLen], 0, cutLen); + + return msgLen - cutLen; +} + +uint8_t Explore_Disk(char* path , uint8_t recu_level) { + char tmp[200]; + char Fstream[200]; + + if (!path) return 0; + + const uint8_t fileCnt = card.get_num_Files(); + + for (uint8_t i = 0; i < fileCnt; i++) { + const uint16_t nr = + #if ENABLED(SDCARD_RATHERRECENTFIRST) && DISABLED(SDCARD_SORT_ALPHA) + fileCnt - 1 - + #endif + i; + + #if ENABLED(SDCARD_SORT_ALPHA) + card.getfilename_sorted(nr); + #else + card.getfilename_sorted(nr); + #endif + memset(tmp, 0, sizeof(tmp)); + strcpy(tmp, card.filename); + + ZERO(Fstream); + strcpy(Fstream, tmp); + + if (card.flag.filenameIsDir && recu_level <= 10) + strcat(Fstream, ".DIR"); + + strcat(Fstream, "\r\n"); + send_to_wifi((uint8_t*)Fstream, strlen(Fstream)); + } + + return fileCnt; +} + +static void wifi_gcode_exec(uint8_t *cmd_line) { + int8_t tempBuf[100] = { 0 }; + uint8_t *tmpStr = 0; + int cmd_value; + volatile int print_rate; + if (strchr((char *)cmd_line, '\n') && (strchr((char *)cmd_line, 'G') || strchr((char *)cmd_line, 'M') || strchr((char *)cmd_line, 'T'))) { + tmpStr = (uint8_t *)strchr((char *)cmd_line, '\n'); + if (tmpStr) *tmpStr = '\0'; + + tmpStr = (uint8_t *)strchr((char *)cmd_line, '\r'); + if (tmpStr) *tmpStr = '\0'; + + tmpStr = (uint8_t *)strchr((char *)cmd_line, '*'); + if (tmpStr) *tmpStr = '\0'; + + tmpStr = (uint8_t *)strchr((char *)cmd_line, 'M'); + if (tmpStr) { + cmd_value = atoi((char *)(tmpStr + 1)); + tmpStr = (uint8_t *)strchr((char *)tmpStr, ' '); + + switch (cmd_value) { + + case 20: // M20: Print SD / µdisk file + file_writer.fileTransfer = 0; + if (uiCfg.print_state == IDLE) { + int index = 0; + + if (tmpStr == 0) { + gCfgItems.fileSysType = FILE_SYS_SD; + send_to_wifi((uint8_t *)"Begin file list\r\n", strlen("Begin file list\r\n")); + get_file_list((char *)"0:/"); + send_to_wifi((uint8_t *)"End file list\r\n", strlen("End file list\r\n")); + SEND_OK_TO_WIFI; + break; + } + + while (tmpStr[index] == ' ') index++; + + if (gCfgItems.wifi_type == ESP_WIFI) { + char *path = (char *)tempBuf; + + if (strlen((char *)&tmpStr[index]) < 80) { + send_to_wifi((uint8_t *)"Begin file list\r\n", strlen("Begin file list\r\n")); + + if (strncmp((char *)&tmpStr[index], "1:", 2) == 0) + gCfgItems.fileSysType = FILE_SYS_SD; + else if (strncmp((char *)&tmpStr[index], "0:", 2) == 0) + gCfgItems.fileSysType = FILE_SYS_USB; + + strcpy((char *)path, (char *)&tmpStr[index]); + get_file_list(path); + send_to_wifi((uint8_t *)"End file list\r\n", strlen("End file list\r\n")); + } + SEND_OK_TO_WIFI; + } + } + break; + + case 21: + /*init sd card*/ + SEND_OK_TO_WIFI; + break; + + case 23: + /*select the file*/ + if (uiCfg.print_state == IDLE) { + int index = 0; + while (tmpStr[index] == ' ') index++; + + if (strstr((char *)&tmpStr[index], ".g") || strstr((char *)&tmpStr[index], ".G")) { + if (strlen((char *)&tmpStr[index]) < 80) { + ZERO(list_file.file_name[sel_id]); + ZERO(list_file.long_name[sel_id]); + uint8_t has_path_selected = 0; + + if (gCfgItems.wifi_type == ESP_WIFI) { + if (strncmp((char *)&tmpStr[index], "1:", 2) == 0) { + gCfgItems.fileSysType = FILE_SYS_SD; + has_path_selected = 1; + } + else if (strncmp((char *)&tmpStr[index], "0:", 2) == 0) { + gCfgItems.fileSysType = FILE_SYS_USB; + has_path_selected = 1; + } + else if (tmpStr[index] != '/') + strcat((char *)list_file.file_name[sel_id], "/"); + + if (file_writer.fileTransfer == 1) { + uint8_t dosName[FILENAME_LENGTH]; + uint8_t fileName[sizeof(list_file.file_name[sel_id])]; + fileName[0] = '\0'; + if (has_path_selected == 1) { + strcat((char *)fileName, (char *)&tmpStr[index + 3]); + strcat((char *)list_file.file_name[sel_id], "/"); + } + else strcat((char *)fileName, (char *)&tmpStr[index]); + if (!longName2DosName((const char *)fileName, dosName)) { + strcpy(list_file.file_name[sel_id], "notValid"); + } + strcat((char *)list_file.file_name[sel_id], (char *)dosName); + strcat((char *)list_file.long_name[sel_id], (char *)dosName); + } + else { + strcat((char *)list_file.file_name[sel_id], (char *)&tmpStr[index]); + strcat((char *)list_file.long_name[sel_id], (char *)&tmpStr[index]); + } + + } + else + strcpy(list_file.file_name[sel_id], (char *)&tmpStr[index]); + + char *cur_name=strrchr(list_file.file_name[sel_id],'/'); + + card.openFileRead(cur_name); + + if (card.isFileOpen()) + send_to_wifi((uint8_t *)"File selected\r\n", strlen("File selected\r\n")); + else { + send_to_wifi((uint8_t *)"file.open failed\r\n", strlen("file.open failed\r\n")); + strcpy(list_file.file_name[sel_id], "notValid"); + } + SEND_OK_TO_WIFI; + } + } + } + break; + + case 24: + if (strcmp(list_file.file_name[sel_id], "notValid") != 0) { + if (uiCfg.print_state == IDLE) { + lv_clear_cur_ui(); + reset_print_time(); + start_print_time(); + preview_gcode_prehandle(list_file.file_name[sel_id]); + uiCfg.print_state = WORKING; + lv_draw_printing(); + + #if ENABLED(SDSUPPORT) + if (!gcode_preview_over) { + char *cur_name = strrchr(list_file.file_name[sel_id], '/'); + + card.endFilePrint(); + + SdFile file; + SdFile *curDir; + card.endFilePrint(); + const char * const fname = card.diveToFile(true, curDir, cur_name); + if (!fname) return; + if (file.open(curDir, fname, O_READ)) { + gCfgItems.curFilesize = file.fileSize(); + file.close(); + update_spi_flash(); + } + card.openFileRead(cur_name); + if (card.isFileOpen()) { + //saved_feedrate_percentage = feedrate_percentage; + feedrate_percentage = 100; + planner.flow_percentage[0] = 100; + planner.e_factor[0] = planner.flow_percentage[0] * 0.01f; + #if EXTRUDERS == 2 + planner.flow_percentage[1] = 100; + planner.e_factor[1] = planner.flow_percentage[1] * 0.01f; + #endif + card.startFileprint(); + TERN_(POWER_LOSS_RECOVERY, recovery.prepare()); + once_flag = false; + } + } + #endif + } + else if (uiCfg.print_state == PAUSED) { + uiCfg.print_state = RESUMING; + lv_clear_cur_ui(); + start_print_time(); + + if (gCfgItems.from_flash_pic) + flash_preview_begin = true; + else + default_preview_flg = true; + lv_draw_printing(); + } + else if (uiCfg.print_state == REPRINTING) { + uiCfg.print_state = REPRINTED; + lv_clear_cur_ui(); + start_print_time(); + if (gCfgItems.from_flash_pic) + flash_preview_begin = true; + else + default_preview_flg = true; + lv_draw_printing(); + } + } + SEND_OK_TO_WIFI; + break; + + case 25: + /*pause print file*/ + if (uiCfg.print_state == WORKING) { + stop_print_time(); + + lv_clear_cur_ui(); + + #if ENABLED(SDSUPPORT) + card.pauseSDPrint(); + uiCfg.print_state = PAUSING; + #endif + if (gCfgItems.from_flash_pic) + flash_preview_begin = true; + else + default_preview_flg = true; + lv_draw_printing(); + SEND_OK_TO_WIFI; + } + break; + + case 26: + /*stop print file*/ + if ((uiCfg.print_state == WORKING) || (uiCfg.print_state == PAUSED) || (uiCfg.print_state == REPRINTING)) { + stop_print_time(); + + lv_clear_cur_ui(); + #if ENABLED(SDSUPPORT) + uiCfg.print_state = IDLE; + card.flag.abort_sd_printing = true; + #endif + + lv_draw_ready_print(); + + SEND_OK_TO_WIFI; + } + break; + + case 27: + /*report print rate*/ + if ((uiCfg.print_state == WORKING) || (uiCfg.print_state == PAUSED)|| (uiCfg.print_state == REPRINTING)) { + print_rate = uiCfg.totalSend; + ZERO(tempBuf); + sprintf((char *)tempBuf, "M27 %d\r\n", print_rate); + send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + } + break; + + case 28: + /*begin to transfer file to filesys*/ + if (uiCfg.print_state == IDLE) { + + int index = 0; + while (tmpStr[index] == ' ') index++; + + if (strstr((char *)&tmpStr[index], ".g") || strstr((char *)&tmpStr[index], ".G")) { + strcpy((char *)file_writer.saveFileName, (char *)&tmpStr[index]); + + if (gCfgItems.fileSysType == FILE_SYS_SD) { + ZERO(tempBuf); + sprintf((char *)tempBuf, "%s", file_writer.saveFileName); + } + else if (gCfgItems.fileSysType == FILE_SYS_USB) { + ZERO(tempBuf); + sprintf((char *)tempBuf, "%s", (char *)file_writer.saveFileName); + } + mount_file_sys(gCfgItems.fileSysType); + + #if ENABLED(SDSUPPORT) + char *cur_name = strrchr(list_file.file_name[sel_id], '/'); + card.openFileWrite(cur_name); + if (card.isFileOpen()) { + ZERO(file_writer.saveFileName); + strcpy((char *)file_writer.saveFileName, (char *)&tmpStr[index]); + ZERO(tempBuf); + sprintf((char *)tempBuf, "Writing to file: %s\r\n", (char *)file_writer.saveFileName); + wifi_ret_ack(); + send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + wifi_link_state = WIFI_WAIT_TRANS_START; + } + else { + wifi_link_state = WIFI_CONNECTED; + lv_clear_cur_ui(); + lv_draw_dialog(DIALOG_TRANSFER_NO_DEVICE); + } + #endif + } + } + break; + case 105: + case 991: + ZERO(tempBuf); + if (cmd_value == 105) { + SEND_OK_TO_WIFI; + sprintf((char *)tempBuf,"T:%.1f /%.1f B:%.1f /%.1f T0:%.1f /%.1f T1:%.1f /%.1f @:0 B@:0\r\n", + + (float)thermalManager.temp_hotend[0].celsius, (float)thermalManager.temp_hotend[0].target, + #if HAS_HEATED_BED + (float)thermalManager.temp_bed.celsius, (float)thermalManager.temp_bed.target, + #else + 0.0f, 0.0f, + #endif + (float)thermalManager.temp_hotend[0].celsius, (float)thermalManager.temp_hotend[0].target, + #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER + (float)thermalManager.temp_hotend[1].celsius, (float)thermalManager.temp_hotend[1].target + #else + 0.0f, 0.0f + #endif + ); + } + else { + sprintf((char *)tempBuf,"T:%d /%d B:%d /%d T0:%d /%d T1:%d /%d @:0 B@:0\r\n", + + (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target, + #if HAS_HEATED_BED + (int)thermalManager.temp_bed.celsius, (int)thermalManager.temp_bed.target, + #else + 0, 0, + #endif + (int)thermalManager.temp_hotend[0].celsius, (int)thermalManager.temp_hotend[0].target, + #if DISABLED(SINGLENOZZLE) && HAS_MULTI_EXTRUDER + (int)thermalManager.temp_hotend[1].celsius, (int)thermalManager.temp_hotend[1].target + #else + 0, 0 + #endif + ); + } + + send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + queue.enqueue_one_P(PSTR("M105")); + break; + + case 992: + if ((uiCfg.print_state == WORKING) || (uiCfg.print_state == PAUSED)) { + ZERO(tempBuf); + sprintf((char *)tempBuf, "M992 %d%d:%d%d:%d%d\r\n", print_time.hours/10, print_time.hours%10, print_time.minutes/10, print_time.minutes%10, print_time.seconds/10, print_time.seconds%10); + wifi_ret_ack(); + send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + } + break; + + case 994: + if ((uiCfg.print_state == WORKING) || (uiCfg.print_state == PAUSED)) { + ZERO(tempBuf); + if (strlen((char *)list_file.file_name[sel_id]) > (100 - 1)) return; + sprintf((char *)tempBuf, "M994 %s;%d\n", list_file.file_name[sel_id],(int)gCfgItems.curFilesize); + wifi_ret_ack(); + send_to_wifi((uint8_t *)tempBuf, strlen((char *)tempBuf)); + } + break; + + case 997: + if (uiCfg.print_state == IDLE) { + wifi_ret_ack(); + send_to_wifi((uint8_t *)"M997 IDLE\r\n", strlen("M997 IDLE\r\n")); + } + else if (uiCfg.print_state == WORKING) { + wifi_ret_ack(); + send_to_wifi((uint8_t *)"M997 PRINTING\r\n", strlen("M997 PRINTING\r\n")); + } + else if (uiCfg.print_state == PAUSED) { + wifi_ret_ack(); + send_to_wifi((uint8_t *)"M997 PAUSE\r\n", strlen("M997 PAUSE\r\n")); + } + else if (uiCfg.print_state == REPRINTING) { + wifi_ret_ack(); + send_to_wifi((uint8_t *)"M997 PAUSE\r\n", strlen("M997 PAUSE\r\n")); + } + if (uiCfg.command_send == 0) get_wifi_list_command_send(); + break; + + case 998: + if (uiCfg.print_state == IDLE) { + int v = atoi((char *)tmpStr); + if (v == 0) + set_cur_file_sys(0); + else if (v == 1) + set_cur_file_sys(1); + wifi_ret_ack(); + } + break; + + case 115: + ZERO(tempBuf); + SEND_OK_TO_WIFI; + send_to_wifi((uint8_t *)"FIRMWARE_NAME:Robin_nano\r\n", strlen("FIRMWARE_NAME:Robin_nano\r\n")); + break; + + default: + strcat((char *)cmd_line, "\n"); + + if (espGcodeFifo.wait_tick > 5) { + uint32_t left; + if (espGcodeFifo.r > espGcodeFifo.w) + left = espGcodeFifo.r - espGcodeFifo.w - 1; + else + left = WIFI_GCODE_BUFFER_SIZE + espGcodeFifo.r - espGcodeFifo.w - 1; + + if (left >= strlen((const char *)cmd_line)) { + uint32_t index = 0; + while (index < strlen((const char *)cmd_line)) { + espGcodeFifo.Buffer[espGcodeFifo.w] = cmd_line[index] ; + espGcodeFifo.w = (espGcodeFifo.w + 1) % WIFI_GCODE_BUFFER_SIZE; + index++; + } + if (left - WIFI_GCODE_BUFFER_LEAST_SIZE >= strlen((const char *)cmd_line)) + SEND_OK_TO_WIFI; + else + need_ok_later = true; + } + } + break; + } + } + else { + strcat((char *)cmd_line, "\n"); + + if (espGcodeFifo.wait_tick > 5) { + uint32_t left_g; + if (espGcodeFifo.r > espGcodeFifo.w) + left_g = espGcodeFifo.r - espGcodeFifo.w - 1; + else + left_g = WIFI_GCODE_BUFFER_SIZE + espGcodeFifo.r - espGcodeFifo.w - 1; + + if (left_g >= strlen((const char *)cmd_line)) { + uint32_t index = 0; + while (index < strlen((const char *)cmd_line)) { + espGcodeFifo.Buffer[espGcodeFifo.w] = cmd_line[index] ; + espGcodeFifo.w = (espGcodeFifo.w + 1) % WIFI_GCODE_BUFFER_SIZE; + index++; + } + if (left_g - WIFI_GCODE_BUFFER_LEAST_SIZE >= strlen((const char *)cmd_line)) + SEND_OK_TO_WIFI; + else + need_ok_later = true; + } + } + } + } +} + +static int32_t charAtArray(const uint8_t *_array, uint32_t _arrayLen, uint8_t _char) { + for (uint32_t i = 0; i < _arrayLen; i++) + if (*(_array + i) == _char) return i; + return -1; +} + +void get_wifi_list_command_send() { + uint8_t cmd_wifi_list[] = { 0xA5, 0x07, 0x00, 0x00, 0xFC }; + raw_send_to_wifi(cmd_wifi_list, COUNT(cmd_wifi_list)); +} + +static void net_msg_handle(uint8_t * msg, uint16_t msgLen) { + int wifiNameLen, wifiKeyLen, hostLen, id_len, ver_len; + + if (msgLen <= 0) return; + + // ip + sprintf(ipPara.ip_addr, "%d.%d.%d.%d", msg[0], msg[1], msg[2], msg[3]); + + // port + // connect state + switch (msg[6]) { + case 0x0A: wifi_link_state = WIFI_CONNECTED; break; + case 0x0E: wifi_link_state = WIFI_EXCEPTION; break; + default: wifi_link_state = WIFI_NOT_CONFIG; break; + } + + // mode + wifiPara.mode = msg[7]; + + // wifi name + wifiNameLen = msg[8]; + wifiKeyLen = msg[9 + wifiNameLen]; + if (wifiNameLen < 32) { + ZERO(wifiPara.ap_name); + memcpy(wifiPara.ap_name, &msg[9], wifiNameLen); + + memset(&wifi_list.wifiConnectedName, 0, sizeof(wifi_list.wifiConnectedName)); + memcpy(&wifi_list.wifiConnectedName, &msg[9], wifiNameLen); + + // wifi key + if (wifiKeyLen < 64) { + ZERO(wifiPara.keyCode); + memcpy(wifiPara.keyCode, &msg[10 + wifiNameLen], wifiKeyLen); + } + } + + cloud_para.state =msg[10 + wifiNameLen + wifiKeyLen]; + hostLen = msg[11 + wifiNameLen + wifiKeyLen]; + if (cloud_para.state) { + if (hostLen < 96) { + ZERO(cloud_para.hostUrl); + memcpy(cloud_para.hostUrl, &msg[12 + wifiNameLen + wifiKeyLen], hostLen); + } + cloud_para.port = msg[12 + wifiNameLen + wifiKeyLen + hostLen] + (msg[13 + wifiNameLen + wifiKeyLen + hostLen] << 8); + } + + // id + id_len = msg[14 + wifiNameLen + wifiKeyLen + hostLen]; + if (id_len == 20) { + ZERO(cloud_para.id); + memcpy(cloud_para.id, (const char *)&msg[15 + wifiNameLen + wifiKeyLen + hostLen], id_len); + } + ver_len = msg[15 + wifiNameLen + wifiKeyLen + hostLen + id_len]; + if (ver_len < 20) { + ZERO(wifi_firm_ver); + memcpy(wifi_firm_ver, (const char *)&msg[16 + wifiNameLen + wifiKeyLen + hostLen + id_len], ver_len); + } + + if (uiCfg.configWifi == 1) { + if ((wifiPara.mode != gCfgItems.wifi_mode_sel) + || (strncmp(wifiPara.ap_name, (const char *)uiCfg.wifi_name, 32) != 0) + || (strncmp(wifiPara.keyCode, (const char *)uiCfg.wifi_key, 64) != 0)) { + package_to_wifi(WIFI_PARA_SET, (uint8_t *)0, 0); + } + else uiCfg.configWifi = 0; + } + if (cfg_cloud_flag == 1) { + if (((cloud_para.state >> 4) != (char)gCfgItems.cloud_enable) + || (strncmp(cloud_para.hostUrl, (const char *)uiCfg.cloud_hostUrl, 96) != 0) + || (cloud_para.port != uiCfg.cloud_port)) { + package_to_wifi(WIFI_CLOUD_CFG, (uint8_t *)0, 0); + } + else cfg_cloud_flag = 0; + } +} + +static void wifi_list_msg_handle(uint8_t * msg, uint16_t msgLen) { + int wifiNameLen,wifiMsgIdex = 1; + int8_t wifi_name_is_same = 0; + int8_t i, j; + int8_t wifi_name_num = 0; + uint8_t *str = 0; + int8_t valid_name_num; + + if (msgLen <= 0) return; + if (disp_state == KEY_BOARD_UI) return; + + wifi_list.getNameNum = msg[0]; + + if (wifi_list.getNameNum < 20) { + uiCfg.command_send = 1; + ZERO(wifi_list.wifiName); + wifi_name_num = wifi_list.getNameNum; + valid_name_num = 0; + str = wifi_list.wifiName[0]; + + if (wifi_list.getNameNum > 0) wifi_list.currentWifipage = 1; + + for (i = 0; i < wifi_list.getNameNum; i++) { + wifiNameLen = msg[wifiMsgIdex++]; + if (wifiNameLen < 32) { + memset(str, 0, WIFI_NAME_BUFFER_SIZE); + memcpy(str, &msg[wifiMsgIdex], wifiNameLen); + for (j = 0; j < valid_name_num; j++) { + if (strcmp((const char *)str,(const char *)wifi_list.wifiName[j]) == 0) { + wifi_name_is_same = 1; + break; + } + } + if (wifi_name_is_same != 1) { + if (str[0] > 0x80) { + wifi_name_is_same = 1; + } + } + if (wifi_name_is_same == 1) { + wifi_name_is_same = 0; + wifiMsgIdex += wifiNameLen; + wifiMsgIdex += 1; + wifi_name_num--; + //i--; + continue; + } + if (i < WIFI_TOTAL_NUMBER - 1) + str = wifi_list.wifiName[++valid_name_num]; + } + wifiMsgIdex += wifiNameLen; + wifi_list.RSSI[i] = msg[wifiMsgIdex++]; + } + wifi_list.getNameNum = wifi_name_num; + wifi_list.getPage = wifi_list.getNameNum / NUMBER_OF_PAGE + ((wifi_list.getNameNum % NUMBER_OF_PAGE) != 0); + wifi_list.nameIndex = 0; + + if (disp_state == WIFI_LIST_UI) disp_wifi_list(); + } +} + +static void gcode_msg_handle(uint8_t * msg, uint16_t msgLen) { + uint8_t gcodeBuf[100] = { 0 }; + char *index_s, *index_e; + + if (msgLen <= 0) return; + + index_s = (char *)msg; + index_e = (char *)strchr((char *)msg, '\n'); + if (*msg == 'N') { + index_s = (char *)strchr((char *)msg, ' '); + while (*index_s == ' ') index_s++; + } + while ((index_e != 0) && ((int)index_s < (int)index_e)) { + if ((int)(index_e - index_s) < (int)sizeof(gcodeBuf)) { + ZERO(gcodeBuf); + memcpy(gcodeBuf, index_s, index_e - index_s + 1); + wifi_gcode_exec(gcodeBuf); + } + while ((*index_e == '\r') || (*index_e == '\n')) index_e++; + index_s = index_e; + index_e = (char *)strchr(index_s, '\n'); + } +} + +void utf8_2_unicode(uint8_t *source,uint8_t Len) { + uint8_t i = 0, char_i = 0, char_byte_num = 0; + uint16_t u16_h, u16_m, u16_l, u16_value; + uint8_t FileName_unicode[30]; + + ZERO(FileName_unicode); + + while (1) { + char_byte_num = source[i] & 0xF0; + if (source[i] < 0X80) { + //ASCII --1byte + FileName_unicode[char_i] = source[i]; + i += 1; + char_i += 1; + } + else if (char_byte_num == 0XC0 || char_byte_num == 0XD0) { + //--2byte + + u16_h = (((uint16_t)source[i] << 8) & 0x1F00) >> 2; + u16_l = ((uint16_t)source[i + 1] & 0x003F); + u16_value = (u16_h | u16_l); + FileName_unicode[char_i] = (uint8_t)((u16_value & 0xFF00) >> 8); + FileName_unicode[char_i + 1] = (uint8_t)(u16_value & 0x00FF); + i += 2; + char_i += 2; + } + else if (char_byte_num == 0XE0) { + //--3byte + u16_h = (((uint16_t)source[i] << 8) & 0x0F00) << 4; + u16_m = (((uint16_t)source[i + 1] << 8) & 0x3F00) >> 2; + u16_l = ((uint16_t)source[i + 2] & 0x003F); + u16_value = (u16_h | u16_m | u16_l); + FileName_unicode[char_i] = (uint8_t)((u16_value & 0xFF00) >> 8); + FileName_unicode[char_i + 1] = (uint8_t)(u16_value & 0x00FF); + i += 3; + char_i += 2; + } + else if (char_byte_num == 0XF0) { + //--4byte + i += 4; + //char_i += 3; + } + else { + break; + } + if (i >= Len || i >= 255) break; + } + COPY(source, FileName_unicode); +} + +static void file_first_msg_handle(uint8_t * msg, uint16_t msgLen) { + uint8_t fileNameLen = *msg; + + if (msgLen != fileNameLen + 5) return; + + file_writer.fileLen = *((uint32_t *)(msg + 1)); + ZERO(file_writer.saveFileName); + + memcpy(file_writer.saveFileName, msg + 5, fileNameLen); + + utf8_2_unicode(file_writer.saveFileName,fileNameLen); + + ZERO(public_buf); + + if (strlen((const char *)file_writer.saveFileName) > sizeof(saveFilePath)) + return; + + ZERO(saveFilePath); + + if (gCfgItems.fileSysType == FILE_SYS_SD) { + TERN_(SDSUPPORT, card.mount()); + } + else if (gCfgItems.fileSysType == FILE_SYS_USB) { + + } + file_writer.write_index = 0; + lastFragment = -1; + + wifiTransError.flag = 0; + wifiTransError.start_tick = 0; + wifiTransError.now_tick = 0; + + TERN_(SDSUPPORT, card.closefile()); + + wifi_delay(1000); + + #if ENABLED(SDSUPPORT) + + uint8_t dosName[FILENAME_LENGTH]; + + if (!longName2DosName((const char *)file_writer.saveFileName,dosName)) { + lv_clear_cur_ui(); + upload_result = 2; + wifiTransError.flag = 1; + wifiTransError.start_tick = getWifiTick(); + lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE); + return; + } + sprintf((char *)saveFilePath, "%s", dosName); + + card.cdroot(); + upload_file.close(); + const char * const fname = card.diveToFile(true, upload_curDir, saveFilePath); + + if (!upload_file.open(upload_curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC)) { + lv_clear_cur_ui(); + upload_result = 2; + + wifiTransError.flag = 1; + wifiTransError.start_tick = getWifiTick(); + + lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE); + return; + } + #endif + + wifi_link_state = WIFI_TRANS_FILE; + + upload_result = 1; + + lv_clear_cur_ui(); + lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE); + + lv_task_handler(); + + file_writer.tick_begin = getWifiTick(); + + file_writer.fileTransfer = 1; +} + +#define FRAG_MASK ~(1 << 31) + +static void file_fragment_msg_handle(uint8_t * msg, uint16_t msgLen) { + uint32_t frag = *((uint32_t *)msg); + + if ((frag & FRAG_MASK) != (uint32_t)(lastFragment + 1)) { + ZERO(public_buf); + file_writer.write_index = 0; + wifi_link_state = WIFI_CONNECTED; + upload_result = 2; + } + else { + if (write_to_file((char *)msg + 4, msgLen - 4) < 0) { + ZERO(public_buf); + file_writer.write_index = 0; + wifi_link_state = WIFI_CONNECTED; + upload_result = 2; + return; + } + lastFragment = frag; + + if ((frag & (~FRAG_MASK)) != 0) { + wifiDmaRcvFifo.receiveEspData = false; + int res = upload_file.write(public_buf, file_writer.write_index); + if (res == -1) { + upload_file.close(); + const char * const fname = card.diveToFile(true, upload_curDir, saveFilePath); + + if (upload_file.open(upload_curDir, fname, O_WRITE)) { + upload_file.setpos(&pos); + res = upload_file.write(public_buf, file_writer.write_index); + } + } + upload_file.close(); + SdFile file, *curDir; + const char * const fname = card.diveToFile(true, curDir, saveFilePath); + if (file.open(curDir, fname, O_RDWR)) { + gCfgItems.curFilesize = file.fileSize(); + file.close(); + } + else { + ZERO(public_buf); + file_writer.write_index = 0; + wifi_link_state = WIFI_CONNECTED; + upload_result = 2; + return; + } + ZERO(public_buf); + file_writer.write_index = 0; + file_writer.tick_end = getWifiTick(); + upload_time = getWifiTickDiff(file_writer.tick_begin, file_writer.tick_end) / 1000; + upload_size = gCfgItems.curFilesize; + wifi_link_state = WIFI_CONNECTED; + upload_result = 3; + } + + } +} + +void esp_data_parser(char *cmdRxBuf, int len) { + int32_t head_pos; + int32_t tail_pos; + uint16_t cpyLen; + int16_t leftLen = len; + bool loop_again = false; + + ESP_PROTOC_FRAME esp_frame; + + while (leftLen > 0 || loop_again) { + loop_again = false; + + if (esp_msg_index != 0) { + head_pos = 0; + cpyLen = (leftLen < (int16_t)((sizeof(esp_msg_buf) - esp_msg_index)) ? leftLen : sizeof(esp_msg_buf) - esp_msg_index); + + memcpy(&esp_msg_buf[esp_msg_index], cmdRxBuf + len - leftLen, cpyLen); + + esp_msg_index += cpyLen; + + leftLen = leftLen - cpyLen; + tail_pos = charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_TAIL); + + if (tail_pos == -1) { + if (esp_msg_index >= sizeof(esp_msg_buf)) { + ZERO(esp_msg_buf); + esp_msg_index = 0; + } + return; + } + } + else { + head_pos = charAtArray((uint8_t const *)&cmdRxBuf[len - leftLen], leftLen, ESP_PROTOC_HEAD); + if (head_pos == -1) return; + + ZERO(esp_msg_buf); + memcpy(esp_msg_buf, &cmdRxBuf[len - leftLen + head_pos], leftLen - head_pos); + + esp_msg_index = leftLen - head_pos; + + leftLen = 0; + head_pos = 0; + tail_pos = charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_TAIL); + if (tail_pos == -1) { + if (esp_msg_index >= sizeof(esp_msg_buf)) { + ZERO(esp_msg_buf); + esp_msg_index = 0; + } + return; + } + } + + esp_frame.type = esp_msg_buf[1]; + if ( esp_frame.type != ESP_TYPE_NET + && esp_frame.type != ESP_TYPE_GCODE + && esp_frame.type != ESP_TYPE_FILE_FIRST + && esp_frame.type != ESP_TYPE_FILE_FRAGMENT + && esp_frame.type != ESP_TYPE_WIFI_LIST + ) { + ZERO(esp_msg_buf); + esp_msg_index = 0; + return; + } + + esp_frame.dataLen = esp_msg_buf[2] + (esp_msg_buf[3] << 8); + + if ((int)(4 + esp_frame.dataLen) > (int)(sizeof(esp_msg_buf))) { + ZERO(esp_msg_buf); + esp_msg_index = 0; + return; + } + + if (esp_msg_buf[4 + esp_frame.dataLen] != ESP_PROTOC_TAIL) { + if (esp_msg_index >= sizeof(esp_msg_buf)) { + ZERO(esp_msg_buf); + esp_msg_index = 0; + } + return; + } + + esp_frame.data = &esp_msg_buf[4]; + switch (esp_frame.type) { + case ESP_TYPE_NET: + net_msg_handle(esp_frame.data, esp_frame.dataLen); + break; + case ESP_TYPE_GCODE: + gcode_msg_handle(esp_frame.data, esp_frame.dataLen); + break; + case ESP_TYPE_FILE_FIRST: + file_first_msg_handle(esp_frame.data, esp_frame.dataLen); + break; + case ESP_TYPE_FILE_FRAGMENT: + file_fragment_msg_handle(esp_frame.data, esp_frame.dataLen); + break; + case ESP_TYPE_WIFI_LIST: + wifi_list_msg_handle(esp_frame.data, esp_frame.dataLen); + break; + default: break; + } + + esp_msg_index = cut_msg_head(esp_msg_buf, esp_msg_index, esp_frame.dataLen + 5); + if (esp_msg_index > 0) { + if (charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_HEAD) == -1) { + ZERO(esp_msg_buf); + esp_msg_index = 0; + return; + } + + if ((charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_HEAD) != -1) && (charAtArray(esp_msg_buf, esp_msg_index, ESP_PROTOC_TAIL) != -1)) + loop_again = true; + } + } +} + +int32_t tick_net_time1, tick_net_time2; +int32_t readWifiFifo(uint8_t *retBuf, uint32_t bufLen) { + unsigned char tmpR = wifiDmaRcvFifo.read_cur; + if (bufLen >= UDISKBUFLEN && wifiDmaRcvFifo.state[tmpR] == udisk_buf_full) { + memcpy(retBuf, (unsigned char *)wifiDmaRcvFifo.bufferAddr[tmpR], UDISKBUFLEN); + wifiDmaRcvFifo.state[tmpR] = udisk_buf_empty; + wifiDmaRcvFifo.read_cur = (tmpR + 1) % TRANS_RCV_FIFO_BLOCK_NUM; + return UDISKBUFLEN; + } + return 0; +} + +void stopEspTransfer() { + if (wifi_link_state == WIFI_TRANS_FILE) + wifi_link_state = WIFI_CONNECTED; + + TERN_(SDSUPPORT, card.closefile()); + + if (upload_result != 3) { + wifiTransError.flag = 1; + wifiTransError.start_tick = getWifiTick(); + card.removeFile((const char *)saveFilePath); + } + + wifi_delay(200); + + WIFI_IO1_SET(); + + // disable dma + #ifdef __STM32F1__ + dma_clear_isr_bits(DMA1, DMA_CH5); + bb_peri_set_bit(&USART1_BASE->CR3, USART_CR3_DMAR_BIT, 0); + dma_disable(DMA1, DMA_CH5); + #else + // First, abort any running dma + HAL_DMA_Abort(&wifiUsartDMArx); + // DeInit objects + HAL_DMA_DeInit(&wifiUsartDMArx); + #endif + + wifi_delay(200); + + exchangeFlashMode(1); //change spi flash to use dma mode + + esp_port_begin(1); + + wifi_delay(200); + + W25QXX.init(SPI_QUARTER_SPEED); + + #if HAS_TFT_LVGL_UI_SPI + SPI_TFT.spi_init(SPI_FULL_SPEED); + #endif + + TERN_(HAS_SERVOS, servo_init()); + + TERN_(HAS_Z_SERVO_PROBE, probe.servo_probe_init()); + + if (wifiTransError.flag != 0x1) + WIFI_IO1_RESET(); +} + +void wifi_rcv_handle() { + int32_t len = 0; + uint8_t ucStr[(UART_RX_BUFFER_SIZE) + 1] = {0}; + int8_t getDataF = 0; + + if (wifi_link_state == WIFI_TRANS_FILE) { + #if 0 + if (WIFISERIAL.available() == UART_RX_BUFFER_SIZE) { + for (uint16_t i=0;i<UART_RX_BUFFER_SIZE;i++) { + ucStr[i] = WIFISERIAL.read(); + len++; + } + } + #else + #ifndef __STM32F1__ + if (wifiDmaRcvFifo.receiveEspData) storeRcvData(WIFISERIAL.wifiRxBuf, UART_RX_BUFFER_SIZE); + #endif + len = readWifiFifo(ucStr, UART_RX_BUFFER_SIZE); + #endif + if (len > 0) { + esp_data_parser((char *)ucStr, len); + if (wifi_link_state == WIFI_CONNECTED) { + lv_clear_cur_ui(); + lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE); + stopEspTransfer(); + } + getDataF = 1; + } + #ifdef __STM32F1__ + if (esp_state == TRANSFER_STORE) { + if (storeRcvData(WIFISERIAL.wifiRxBuf, UART_RX_BUFFER_SIZE)) { + esp_state = TRANSFERING; + esp_dma_pre(); + if (wifiTransError.flag != 0x1) WIFI_IO1_RESET(); + } + else WIFI_IO1_SET(); + } + #endif + } + else { + len = readWifiBuf((int8_t *)ucStr, UART_RX_BUFFER_SIZE); + if (len > 0) { + esp_data_parser((char *)ucStr, len); + + if (wifi_link_state == WIFI_TRANS_FILE) { + exchangeFlashMode(0); //change spi flash not use dma mode + + wifi_delay(10); + + esp_port_begin(0); + + wifi_delay(10); + + tick_net_time1 = 0; + #ifndef __STM32F1__ + wifiDmaRcvFifo.receiveEspData = true; + return; + #endif + } + if (wifiTransError.flag != 0x1) { + WIFI_IO1_RESET(); + } + getDataF = 1; + } + if (need_ok_later && (queue.length < BUFSIZE)) { + need_ok_later = false; + send_to_wifi((uint8_t *)"ok\r\n", strlen("ok\r\n")); + } + } + + if (getDataF == 1) { + tick_net_time1 = getWifiTick(); + } + else { + tick_net_time2 = getWifiTick(); + + if (wifi_link_state == WIFI_TRANS_FILE) { + if ((tick_net_time1 != 0) && (getWifiTickDiff(tick_net_time1, tick_net_time2) > 8000)) { + wifi_link_state = WIFI_CONNECTED; + + upload_result = 2; + + lv_clear_cur_ui(); + + stopEspTransfer(); + + lv_draw_dialog(DIALOG_TYPE_UPLOAD_FILE); + } + } + if ((tick_net_time1 != 0) && (getWifiTickDiff(tick_net_time1, tick_net_time2) > 10000)) { + wifi_link_state = WIFI_NOT_CONFIG; + } + if ((tick_net_time1 != 0) && (getWifiTickDiff(tick_net_time1, tick_net_time2) > 120000)) { + wifi_link_state = WIFI_NOT_CONFIG; + + wifi_reset(); + + tick_net_time1 = getWifiTick(); + } + } + + if (wifiTransError.flag == 0x1) { + wifiTransError.now_tick = getWifiTick(); + if (getWifiTickDiff(wifiTransError.start_tick, wifiTransError.now_tick) > WAIT_ESP_TRANS_TIMEOUT_TICK) { + wifiTransError.flag = 0; + WIFI_IO1_RESET(); + } + } +} + +void wifi_looping() { + do { + wifi_rcv_handle(); + watchdog_refresh(); + } while (wifi_link_state == WIFI_TRANS_FILE); +} + +void mks_esp_wifi_init() { + wifi_link_state = WIFI_NOT_CONFIG; + + SET_OUTPUT(WIFI_RESET_PIN); + WIFI_SET(); + SET_OUTPUT(WIFI_IO1_PIN); + SET_INPUT_PULLUP(WIFI_IO0_PIN); + WIFI_IO1_SET(); + + esp_state = TRANSFER_IDLE; + esp_port_begin(1); + + wifi_reset(); + + #if 0 + if (update_flag == 0) { + res = f_open(&esp_upload.uploadFile, ESP_WEB_FIRMWARE_FILE, FA_OPEN_EXISTING | FA_READ); + + if (res == FR_OK) { + f_close(&esp_upload.uploadFile); + + wifi_delay(2000); + + if (usartFifoAvailable((SZ_USART_FIFO *)&WifiRxFifo) < 20) { + return; + } + + lv_clear_cur_ui(); + + draw_dialog(DIALOG_TYPE_UPDATE_ESP_FIRMARE); + if (wifi_upload(1) >= 0) { + + f_unlink("1:/MKS_WIFI_CUR"); + f_rename(ESP_WEB_FIRMWARE_FILE,"/MKS_WIFI_CUR"); + } + lv_draw_return_ui(); + update_flag = 1; + } + + } + if (update_flag == 0) { + res = f_open(&esp_upload.uploadFile, ESP_WEB_FILE, FA_OPEN_EXISTING | FA_READ); + if (res == FR_OK) { + f_close(&esp_upload.uploadFile); + + wifi_delay(2000); + + if (usartFifoAvailable((SZ_USART_FIFO *)&WifiRxFifo) < 20) { + return; + } + + lv_clear_cur_ui(); + + draw_dialog(DIALOG_TYPE_UPDATE_ESP_DATA); + + if (wifi_upload(2) >= 0) { + + f_unlink("1:/MKS_WEB_CONTROL_CUR"); + f_rename(ESP_WEB_FILE,"/MKS_WEB_CONTROL_CUR"); + } + lv_draw_return_ui(); + } + } + #endif + wifiPara.decodeType = WIFI_DECODE_TYPE; + wifiPara.baud = 115200; + wifi_link_state = WIFI_NOT_CONFIG; +} + + +void mks_wifi_firmware_upddate() { + card.openFileRead((char *)ESP_FIRMWARE_FILE); + + if (card.isFileOpen()) { + card.closefile(); + + wifi_delay(2000); + + if (usartFifoAvailable((SZ_USART_FIFO *)&WifiRxFifo) < 20) + return; + + lv_clear_cur_ui(); + + lv_draw_dialog(DIALOG_TYPE_UPDATE_ESP_FIRMARE); + + lv_task_handler(); + watchdog_refresh(); + + if (wifi_upload(0) >= 0) { + card.removeFile((char *)ESP_FIRMWARE_FILE_RENAME); + SdFile file, *curDir; + const char * const fname = card.diveToFile(true, curDir, ESP_FIRMWARE_FILE); + if (file.open(curDir, fname, O_READ)) { + file.rename(curDir, (char *)ESP_FIRMWARE_FILE_RENAME); + file.close(); + } + } + lv_clear_cur_ui(); + } +} + +void get_wifi_commands() { + static char wifi_line_buffer[MAX_CMD_SIZE]; + static bool wifi_comment_mode = false; + static int wifi_read_count = 0; + + if (espGcodeFifo.wait_tick > 5) { + while ((queue.length < BUFSIZE) && (espGcodeFifo.r != espGcodeFifo.w)) { + + espGcodeFifo.wait_tick = 0; + + char wifi_char = espGcodeFifo.Buffer[espGcodeFifo.r]; + + espGcodeFifo.r = (espGcodeFifo.r + 1) % WIFI_GCODE_BUFFER_SIZE; + + /** + * If the character ends the line + */ + if (wifi_char == '\n' || wifi_char == '\r') { + + wifi_comment_mode = false; // end of line == end of comment + + if (!wifi_read_count) continue; // skip empty lines + + wifi_line_buffer[wifi_read_count] = 0; // terminate string + wifi_read_count = 0; //reset buffer + + char* command = wifi_line_buffer; + while (*command == ' ') command++; // skip any leading spaces + + // Movement commands alert when stopped + if (IsStopped()) { + char* gpos = strchr(command, 'G'); + if (gpos) { + switch (strtol(gpos + 1, nullptr, 10)) { + case 0 ... 1: + #if ENABLED(ARC_SUPPORT) + case 2 ... 3: + #endif + #if ENABLED(BEZIER_CURVE_SUPPORT) + case 5: + #endif + SERIAL_ECHOLNPGM(STR_ERR_STOPPED); + LCD_MESSAGEPGM(MSG_STOPPED); + break; + } + } + } + + #if DISABLED(EMERGENCY_PARSER) + // Process critical commands early + if (strcmp(command, "M108") == 0) { + wait_for_heatup = false; + TERN_(HAS_LCD_MENU, wait_for_user = false); + } + if (strcmp(command, "M112") == 0) kill(M112_KILL_STR, nullptr, true); + if (strcmp(command, "M410") == 0) quickstop_stepper(); + #endif + + // Add the command to the queue + queue.enqueue_one_P(wifi_line_buffer); + } + else if (wifi_read_count >= MAX_CMD_SIZE - 1) { + + } + else { // it's not a newline, carriage return or escape char + if (wifi_char == ';') wifi_comment_mode = true; + if (!wifi_comment_mode) wifi_line_buffer[wifi_read_count++] = wifi_char; + } + } + } // queue has space, serial has data + else + espGcodeFifo.wait_tick++; +} + +int readWifiBuf(int8_t *buf, int32_t len) { + int i = 0; + while (i < len && WIFISERIAL.available()) + buf[i++] = WIFISERIAL.read(); + return i; +} + +int usartFifoAvailable(SZ_USART_FIFO *fifo) { + return WIFISERIAL.available(); +} + +#endif // MKS_WIFI_MODULE +#endif // HAS_TFT_LVGL_UI diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.h b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.h new file mode 100644 index 0000000..856c619 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_module.h @@ -0,0 +1,201 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +#include "../../../../inc/MarlinConfigPre.h" + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> + +#define UART_RX_BUFFER_SIZE 1024 +#define UART_FIFO_BUFFER_SIZE 1024 + +#define WIFI_DECODE_TYPE 1 + +#define IP_DHCP_FLAG 1 + +#define WIFI_AP_NAME "TP-LINK_MKS" +#define WIFI_KEY_CODE "makerbase" + +#define IP_ADDR "192.168.3.100" +#define IP_MASK "255.255.255.0" +#define IP_GATE "192.168.3.1" +#define IP_DNS "192.168.3.1" + +#define AP_IP_DHCP_FLAG 1 +#define AP_IP_ADDR "192.168.3.100" +#define AP_IP_MASK "255.255.255.0" +#define AP_IP_GATE "192.168.3.1" +#define AP_IP_DNS "192.168.3.1" +#define IP_START_IP "192.168.3.1" +#define IP_END_IP "192.168.3.255" + +#define UDISKBUFLEN 1024 + +typedef enum{ + udisk_buf_empty = 0, + udisk_buf_full, +} UDISK_DATA_BUFFER_STATE; + +#define TRANS_RCV_FIFO_BLOCK_NUM 14 + +typedef struct { + bool receiveEspData; + unsigned char *bufferAddr[TRANS_RCV_FIFO_BLOCK_NUM]; + unsigned char *p; + UDISK_DATA_BUFFER_STATE state[TRANS_RCV_FIFO_BLOCK_NUM]; + unsigned char read_cur; + unsigned char write_cur; +} WIFI_DMA_RCV_FIFO; + +typedef struct { + uint8_t flag; // 0x0: no error; 0x01: error + uint32_t start_tick; //error start time + uint32_t now_tick; +} WIFI_TRANS_ERROR; + +extern volatile WIFI_TRANS_ERROR wifiTransError; + +typedef struct { + char ap_name[32]; //wifi-name + char keyCode[64]; //wifi password + int decodeType; + int baud; + int mode; +} WIFI_PARA; + +typedef struct { + char state; + char hostUrl[96]; + int port; + char id[21]; +} CLOUD_PARA; + +typedef struct { + char dhcp_flag; + char ip_addr[16]; + char mask[16]; + char gate[16]; + char dns[16]; + + char dhcpd_flag; + char dhcpd_ip[16]; + char dhcpd_mask[16]; + char dhcpd_gate[16]; + char dhcpd_dns[16]; + char start_ip_addr[16]; + char end_ip_addr[16]; +} IP_PARA; + +typedef enum { + WIFI_NOT_CONFIG, + WIFI_CONFIG_MODE, + WIFI_CONFIG_DHCP, + WIFI_CONFIG_AP, + WIFI_CONFIG_IP_INF, + WIFI_CONFIG_DNS, + WIFI_CONFIG_TCP, + WIFI_CONFIG_SERVER, + WIFI_CONFIG_REMOTE_PORT, + WIFI_CONFIG_BAUD, + WIFI_CONFIG_COMMINT, + WIFI_CONFIG_OK, + WIFI_GET_IP_OK, + WIFI_RECONN, + WIFI_CONNECTED, + WIFI_WAIT_TRANS_START, + WIFI_TRANS_FILE, + WIFI_CONFIG_DHCPD, + WIFI_COFIG_DHCPD_IP, + WIFI_COFIG_DHCPD_DNS, + WIFI_EXCEPTION, +} WIFI_STATE; + +typedef enum { + TRANSFER_IDLE, + TRANSFERING, + TRANSFER_STORE, +} TRANSFER_STATE; +extern volatile TRANSFER_STATE esp_state; + +typedef struct { + char buf[20][80]; + int rd_index; + int wt_index; +} QUEUE; + +typedef enum { + WIFI_PARA_SET, // 0x0:net parameter + WIFI_PRINT_INF, // 0x1:print message + WIFI_TRANS_INF, // 0x2:Pass through information + WIFI_EXCEP_INF, // 0x3:Exception information + WIFI_CLOUD_CFG, // 0x4:cloud config + WIFI_CLOUD_UNBIND, // 0x5:Unbind ID +} WIFI_RET_TYPE; + +typedef struct { + uint32_t uart_read_point; + uint32_t uart_write_point; + //uint8_t uartTxBuffer[UART_FIFO_BUFFER_SIZE]; +} SZ_USART_FIFO; + +#define WIFI_GCODE_BUFFER_LEAST_SIZE 96 +#define WIFI_GCODE_BUFFER_SIZE (WIFI_GCODE_BUFFER_LEAST_SIZE * 3) +typedef struct { + uint8_t wait_tick; + uint8_t Buffer[WIFI_GCODE_BUFFER_SIZE]; + uint32_t r; + uint32_t w; +} WIFI_GCODE_BUFFER; + +extern volatile WIFI_STATE wifi_link_state; +extern WIFI_PARA wifiPara; +extern IP_PARA ipPara; +extern CLOUD_PARA cloud_para; + +extern WIFI_GCODE_BUFFER espGcodeFifo; + +extern uint32_t getWifiTick(); +extern uint32_t getWifiTickDiff(int32_t lastTick, int32_t curTick); + +extern void mks_esp_wifi_init(); +extern int cfg_cloud_flag; +extern int send_to_wifi(uint8_t *buf, int len); +extern void wifi_looping(); +extern int raw_send_to_wifi(uint8_t *buf, int len); +extern int package_to_wifi(WIFI_RET_TYPE type, uint8_t *buf, int len); +extern void get_wifi_list_command_send(); +extern void get_wifi_commands(); +extern int readWifiBuf(int8_t *buf, int32_t len); +extern void mks_wifi_firmware_upddate(); +extern int usartFifoAvailable(SZ_USART_FIFO *fifo); +extern int readUsartFifo(SZ_USART_FIFO *fifo, int8_t *buf, int32_t len); +extern void esp_port_begin(uint8_t interrupt); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp new file mode 100644 index 0000000..da35254 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.cpp @@ -0,0 +1,726 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#include "../../../../inc/MarlinConfigPre.h" + +#if BOTH(HAS_TFT_LVGL_UI, MKS_WIFI_MODULE) + +#include "draw_ui.h" +#include "wifi_module.h" +#include "wifi_upload.h" + +#include "../../../../MarlinCore.h" +#include "../../../../sd/cardreader.h" + +#define WIFI_SET() WRITE(WIFI_RESET_PIN, HIGH); +#define WIFI_RESET() WRITE(WIFI_RESET_PIN, LOW); +#define WIFI_IO1_SET() WRITE(WIFI_IO1_PIN, HIGH); +#define WIFI_IO1_RESET() WRITE(WIFI_IO1_PIN, LOW); + +extern SZ_USART_FIFO WifiRxFifo; + +extern int readUsartFifo(SZ_USART_FIFO *fifo, int8_t *buf, int32_t len); +extern int writeUsartFifo(SZ_USART_FIFO * fifo, int8_t * buf, int32_t len); +extern void esp_port_begin(uint8_t interrupt); +extern void wifi_delay(int n); + +#define ARRAY_SIZE(a) sizeof(a) / sizeof((a)[0]) + +//typedef signed char bool; + +// ESP8266 command codes +const uint8_t ESP_FLASH_BEGIN = 0x02; +const uint8_t ESP_FLASH_DATA = 0x03; +const uint8_t ESP_FLASH_END = 0x04; +const uint8_t ESP_MEM_BEGIN = 0x05; +const uint8_t ESP_MEM_END = 0x06; +const uint8_t ESP_MEM_DATA = 0x07; +const uint8_t ESP_SYNC = 0x08; +const uint8_t ESP_WRITE_REG = 0x09; +const uint8_t ESP_READ_REG = 0x0A; + +// MAC address storage locations +const uint32_t ESP_OTP_MAC0 = 0x3FF00050; +const uint32_t ESP_OTP_MAC1 = 0x3FF00054; +const uint32_t ESP_OTP_MAC2 = 0x3FF00058; +const uint32_t ESP_OTP_MAC3 = 0x3FF0005C; + +const size_t EspFlashBlockSize = 0x0400; // 1K byte blocks + +const uint8_t ESP_IMAGE_MAGIC = 0xE9; +const uint8_t ESP_CHECKSUM_MAGIC = 0xEF; + +const uint32_t ESP_ERASE_CHIP_ADDR = 0x40004984; // &SPIEraseChip +const uint32_t ESP_SEND_PACKET_ADDR = 0x40003C80; // &send_packet +const uint32_t ESP_SPI_READ_ADDR = 0x40004B1C; // &SPIRead +const uint32_t ESP_UNKNOWN_ADDR = 0x40001121; // not used +const uint32_t ESP_USER_DATA_RAM_ADDR = 0x3FFE8000; // &user data ram +const uint32_t ESP_IRAM_ADDR = 0x40100000; // instruction RAM +const uint32_t ESP_FLASH_ADDR = 0x40200000; // address of start of Flash + +UPLOAD_STRUCT esp_upload; + +static const unsigned int retriesPerReset = 3; +static const uint32_t connectAttemptInterval = 50; +static const unsigned int percentToReportIncrement = 5; // how often we report % complete +static const uint32_t defaultTimeout = 500; +static const uint32_t eraseTimeout = 15000; +static const uint32_t blockWriteTimeout = 200; +static const uint32_t blockWriteInterval = 15; // 15ms is long enough, 10ms is mostly too short +static SdFile update_file, *update_curDir; + +// Messages corresponding to result codes, should make sense when followed by " error" +const char *resultMessages[] = { + "no", + "timeout", + "comm write", + "connect", + "bad reply", + "file read", + "empty file", + "response header", + "slip frame", + "slip state", + "slip data" +}; + +// A note on baud rates. +// The ESP8266 supports 921600, 460800, 230400, 115200, 74880 and some lower baud rates. +// 921600b is not reliable because even though it sometimes succeeds in connecting, we get a bad response during uploading after a few blocks. +// Probably our UART ISR cannot receive bytes fast enough, perhaps because of the latency of the system tick ISR. +// 460800b doesn't always manage to connect, but if it does then uploading appears to be reliable. +// 230400b always manages to connect. +static const uint32_t uploadBaudRates[] = { 460800, 230400, 115200, 74880 }; + +signed char IsReady() { + return esp_upload.state == upload_idle; +} + +void uploadPort_write(const uint8_t *buf, size_t len) { + for(size_t i = 0; i < len; i++) { + WIFISERIAL.write(*(buf + i)); + } +} + +char uploadPort_read() { + uint8_t retChar; + retChar = WIFISERIAL.read(); + if (retChar > 0) return retChar; + else return 0; +} + +int uploadPort_available() { + return usartFifoAvailable(&WifiRxFifo); +} + +void uploadPort_begin() { + esp_port_begin(1); +} + +void uploadPort_close() { + //WIFI_COM.end(); + //WIFI_COM.begin(115200, true); + esp_port_begin(0); +} + +void flushInput() { + while (uploadPort_available() != 0) { + (void)uploadPort_read(); + //IWDG_ReloadCounter(); + } +} + +// Extract 1-4 bytes of a value in little-endian order from a buffer beginning at a specified offset +uint32_t getData(unsigned byteCnt, const uint8_t *buf, int ofst) { + uint32_t val = 0; + + if (buf && byteCnt) { + unsigned int shiftCnt = 0; + if (byteCnt > 4) + byteCnt = 4; + do{ + val |= (uint32_t)buf[ofst++] << shiftCnt; + shiftCnt += 8; + } while (--byteCnt); + } + return(val); +} + +// Put 1-4 bytes of a value in little-endian order into a buffer beginning at a specified offset. +void putData(uint32_t val, unsigned byteCnt, uint8_t *buf, int ofst) { + if (buf && byteCnt) { + if (byteCnt > 4) { + byteCnt = 4; + } + do { + buf[ofst++] = (uint8_t)(val & 0xFF); + val >>= 8; + } while (--byteCnt); + } +} + +// Read a byte optionally performing SLIP decoding. The return values are: +// +// 2 - an escaped byte was read successfully +// 1 - a non-escaped byte was read successfully +// 0 - no data was available +// -1 - the value 0xC0 was encountered (shouldn't happen) +// -2 - a SLIP escape byte was found but the following byte wasn't available +// -3 - a SLIP escape byte was followed by an invalid byte +int ReadByte(uint8_t *data, signed char slipDecode) { + if (uploadPort_available() == 0) { + return(0); + } + + // at least one byte is available + *data = uploadPort_read(); + if (!slipDecode) { + return(1); + } + + if (*data == 0xC0) { + // this shouldn't happen + return(-1); + } + + // if not the SLIP escape, we're done + if (*data != 0xDB) { + return(1); + } + + // SLIP escape, check availability of subsequent byte + if (uploadPort_available() == 0) { + return(-2); + } + + // process the escaped byte + *data = uploadPort_read(); + if (*data == 0xDC) { + *data = 0xC0; + return(2); + } + + if (*data == 0xDD) { + *data = 0xDB; + return(2); + } + // invalid + return(-3); +} +// When we write a sync packet, there must be no gaps between most of the characters. +// So use this function, which does a block write to the UART buffer in the latest CoreNG. +void _writePacketRaw(const uint8_t *buf, size_t len) { + uploadPort_write(buf, len); +} + +// Write a byte to the serial port optionally SLIP encoding. Return the number of bytes actually written. +void WriteByteRaw(uint8_t b) { + uploadPort_write((const uint8_t *)&b, 1); +} + +// Write a byte to the serial port optionally SLIP encoding. Return the number of bytes actually written. +void WriteByteSlip(uint8_t b) { + if (b == 0xC0) { + WriteByteRaw(0xDB); + WriteByteRaw(0xDC); + } + else if (b == 0xDB) { + WriteByteRaw(0xDB); + WriteByteRaw(0xDD); + } + else { + uploadPort_write((const uint8_t *)&b, 1); + } +} + +// Wait for a data packet to be returned. If the body of the packet is +// non-zero length, return an allocated buffer indirectly containing the +// data and return the data length. Note that if the pointer for returning +// the data buffer is nullptr, the response is expected to be two bytes of zero. +// +// If an error occurs, return a negative value. Otherwise, return the number +// of bytes in the response (or zero if the response was not the standard "two bytes of zero"). +EspUploadResult readPacket(uint8_t op, uint32_t *valp, size_t *bodyLen, uint32_t msTimeout) { + typedef enum { + begin = 0, + header, + body, + end, + done + } PacketState; + + uint8_t resp, opRet; + + const size_t headerLength = 8; + + uint32_t startTime = getWifiTick(); + uint8_t hdr[headerLength]; + uint16_t hdrIdx = 0; + + uint16_t bodyIdx = 0; + uint8_t respBuf[2]; + + // wait for the response + uint16_t needBytes = 1; + + PacketState state = begin; + + *bodyLen = 0; + + while (state != done) { + uint8_t c; + EspUploadResult stat; + + //IWDG_ReloadCounter(); + watchdog_refresh(); + + if (getWifiTickDiff(startTime, getWifiTick()) > msTimeout) + return timeout; + + if (uploadPort_available() < needBytes) { + // insufficient data available + // preferably, return to Spin() here + continue; + } + + // sufficient bytes have been received for the current state, process them + switch (state) { + case begin: // expecting frame start + c = uploadPort_read(); + if (c != (uint8_t)0xC0) break; + state = header; + needBytes = 2; + break; + case end: // expecting frame end + c = uploadPort_read(); + if (c != (uint8_t)0xC0) return slipFrame; + state = done; + break; + + case header: // reading an 8-byte header + case body: { // reading the response body + int rslt; + // retrieve a byte with SLIP decoding + rslt = ReadByte(&c, 1); + if (rslt != 1 && rslt != 2) { + // some error occurred + stat = (rslt == 0 || rslt == -2) ? slipData : slipFrame; + return stat; + } + else if (state == header) { + //store the header byte + hdr[hdrIdx++] = c; + if (hdrIdx >= headerLength) { + // get the body length, prepare a buffer for it + *bodyLen = (uint16_t)getData(2, hdr, 2); + + // extract the value, if requested + if (valp) + *valp = getData(4, hdr, 4); + + if (*bodyLen != 0) + state = body; + else { + needBytes = 1; + state = end; + } + } + } + else { + // Store the response body byte, check for completion + if (bodyIdx < ARRAY_SIZE(respBuf)) + respBuf[bodyIdx] = c; + + if (++bodyIdx >= *bodyLen) { + needBytes = 1; + state = end; + } + } + } break; + + default: return slipState; // this shouldn't happen + } + } + + // Extract elements from the header + resp = (uint8_t)getData(1, hdr, 0); + opRet = (uint8_t)getData(1, hdr, 1); + // Sync packets often provoke a response with a zero opcode instead of ESP_SYNC + if (resp != 0x01 || opRet != op) { + return respHeader; + } + + return success; +} + +// Send a block of data performing SLIP encoding of the content. +void _writePacket(const uint8_t *data, size_t len) { + unsigned char outBuf[2048] = {0}; + unsigned int outIndex = 0; + while (len != 0) { + if (*data == 0xC0) { + outBuf[outIndex++] = 0xDB; + outBuf[outIndex++] = 0xDC; + } + else if (*data == 0xDB) { + outBuf[outIndex++] = 0xDB; + outBuf[outIndex++] = 0xDD; + } + else { + outBuf[outIndex++] = *data; + } + data++; + --len; + } + uploadPort_write((const uint8_t *)outBuf, outIndex); +} + +// Send a packet to the serial port while performing SLIP framing. The packet data comprises a header and an optional data block. +// A SLIP packet begins and ends with 0xC0. The data encapsulated has the bytes +// 0xC0 and 0xDB replaced by the two-byte sequences {0xDB, 0xDC} and {0xDB, 0xDD} respectively. + +void writePacket(const uint8_t *hdr, size_t hdrLen, const uint8_t *data, size_t dataLen) { + WriteByteRaw(0xC0); // send the packet start character + _writePacket(hdr, hdrLen); // send the header + _writePacket(data, dataLen); // send the data block + WriteByteRaw(0xC0); // send the packet end character +} + +// Send a packet to the serial port while performing SLIP framing. The packet data comprises a header and an optional data block. +// This is like writePacket except that it does a fast block write for both the header and the main data with no SLIP encoding. Used to send sync commands. +void writePacketRaw(const uint8_t *hdr, size_t hdrLen, const uint8_t *data, size_t dataLen) { + WriteByteRaw(0xC0); // send the packet start character + _writePacketRaw(hdr, hdrLen); // send the header + _writePacketRaw(data, dataLen); // send the data block in raw mode + WriteByteRaw(0xC0); // send the packet end character +} + +// Send a command to the attached device together with the supplied data, if any. +// The data is supplied via a list of one or more segments. +void sendCommand(uint8_t op, uint32_t checkVal, const uint8_t *data, size_t dataLen) { + // populate the header + uint8_t hdr[8]; + putData(0, 1, hdr, 0); + putData(op, 1, hdr, 1); + putData(dataLen, 2, hdr, 2); + putData(checkVal, 4, hdr, 4); + + // send the packet + if (op == ESP_SYNC) + writePacketRaw(hdr, sizeof(hdr), data, dataLen); + else + writePacket(hdr, sizeof(hdr), data, dataLen); +} + +// Send a command to the attached device together with the supplied data, if any, and get the response +EspUploadResult doCommand(uint8_t op, const uint8_t *data, size_t dataLen, uint32_t checkVal, uint32_t *valp, uint32_t msTimeout) { + size_t bodyLen; + EspUploadResult stat; + + sendCommand(op, checkVal, data, dataLen); + + stat = readPacket(op, valp, &bodyLen, msTimeout); + if (stat == success && bodyLen != 2) + stat = badReply; + + return stat; +} + +// Send a synchronising packet to the serial port in an attempt to induce +// the ESP8266 to auto-baud lock on the baud rate. +EspUploadResult Sync(uint16_t timeout) { + uint8_t buf[36]; + EspUploadResult stat; + int i ; + + // compose the data for the sync attempt + memset(buf, 0x55, sizeof(buf)); + buf[0] = 0x07; + buf[1] = 0x07; + buf[2] = 0x12; + buf[3] = 0x20; + + stat = doCommand(ESP_SYNC, buf, sizeof(buf), 0, 0, timeout); + + // If we got a response other than sync, discard it and wait for a sync response. This happens at higher baud rates. + for (i = 0; i < 10 && stat == respHeader; ++i) { + size_t bodyLen; + stat = readPacket(ESP_SYNC, 0, &bodyLen, timeout); + } + + if (stat == success) { + // Read and discard additional replies + for (;;) { + size_t bodyLen; + EspUploadResult rc = readPacket(ESP_SYNC, 0, &bodyLen, defaultTimeout); + watchdog_refresh(); + if (rc != success || bodyLen != 2) break; + } + } + //DEBUG + //else debug//printf("stat=%d\n", (int)stat); + return stat; +} + +// Send a command to the device to begin the Flash process. +EspUploadResult flashBegin(uint32_t addr, uint32_t size) { + // determine the number of blocks represented by the size + uint32_t blkCnt; + uint8_t buf[16]; + uint32_t timeout; + + blkCnt = (size + EspFlashBlockSize - 1) / EspFlashBlockSize; + + // ensure that the address is on a block boundary + addr &= ~(EspFlashBlockSize - 1); + + // begin the Flash process + putData(size, 4, buf, 0); + putData(blkCnt, 4, buf, 4); + putData(EspFlashBlockSize, 4, buf, 8); + putData(addr, 4, buf, 12); + + timeout = (size != 0) ? eraseTimeout : defaultTimeout; + return doCommand(ESP_FLASH_BEGIN, buf, sizeof(buf), 0, 0, timeout); +} + +// Send a command to the device to terminate the Flash process +EspUploadResult flashFinish(signed char reboot) { + uint8_t buf[4]; + putData(reboot ? 0 : 1, 4, buf, 0); + return doCommand(ESP_FLASH_END, buf, sizeof(buf), 0, 0, defaultTimeout); +} + +// Compute the checksum of a block of data +uint16_t checksum(const uint8_t *data, uint16_t dataLen, uint16_t cksum) { + if (data) while (dataLen--) cksum ^= (uint16_t)*data++; + return cksum; +} + +EspUploadResult flashWriteBlock(uint16_t flashParmVal, uint16_t flashParmMask) { + const uint32_t blkSize = EspFlashBlockSize; + int i; + + // Allocate a data buffer for the combined header and block data + const uint16_t hdrOfst = 0; + const uint16_t dataOfst = 16; + const uint16_t blkBufSize = dataOfst + blkSize; + uint32_t blkBuf32[blkBufSize/4]; + uint8_t * const blkBuf = (uint8_t*)(blkBuf32); + uint32_t cnt; + uint16_t cksum; + EspUploadResult stat; + + // Prepare the header for the block + putData(blkSize, 4, blkBuf, hdrOfst + 0); + putData(esp_upload.uploadBlockNumber, 4, blkBuf, hdrOfst + 4); + putData(0, 4, blkBuf, hdrOfst + 8); + putData(0, 4, blkBuf, hdrOfst + 12); + + // Get the data for the block + cnt = update_file.read(blkBuf + dataOfst, blkSize);//->Read(reinterpret_cast<char *>(blkBuf + dataOfst), blkSize); + if (cnt != blkSize) { + if (update_file.curPosition() == esp_upload.fileSize) { + // partial last block, fill the remainder + memset(blkBuf + dataOfst + cnt, 0xff, blkSize - cnt); + } + else + return fileRead; + } + + // Patch the flash parameters into the first block if it is loaded at address 0 + if (esp_upload.uploadBlockNumber == 0 && esp_upload.uploadAddress == 0 && blkBuf[dataOfst] == ESP_IMAGE_MAGIC && flashParmMask != 0) { + // update the Flash parameters + uint32_t flashParm = getData(2, blkBuf + dataOfst + 2, 0) & ~(uint32_t)flashParmMask; + putData(flashParm | flashParmVal, 2, blkBuf + dataOfst + 2, 0); + } + + // Calculate the block checksum + cksum = checksum(blkBuf + dataOfst, blkSize, ESP_CHECKSUM_MAGIC); + + for (i = 0; i < 3; i++) + if ((stat = doCommand(ESP_FLASH_DATA, blkBuf, blkBufSize, cksum, 0, blockWriteTimeout)) == success) + break; + return stat; +} + +void upload_spin() { + + switch (esp_upload.state) { + case resetting: + + if (esp_upload.connectAttemptNumber == 9) { + esp_upload.uploadResult = connected; + esp_upload.state = done; + } + else{ + uploadPort_begin(); + + wifi_delay(2000); + + flushInput(); + + esp_upload.lastAttemptTime = esp_upload.lastResetTime = getWifiTick(); + esp_upload.state = connecting; + } + + break; + + case connecting: + if ((getWifiTickDiff(esp_upload.lastAttemptTime, getWifiTick()) >= connectAttemptInterval) && (getWifiTickDiff(esp_upload.lastResetTime, getWifiTick()) >= 500)) { + EspUploadResult res = Sync(5000); + esp_upload.lastAttemptTime = getWifiTick(); + if (res == success) { + esp_upload.state = erasing; + } + else { + esp_upload.connectAttemptNumber++; + if (esp_upload.connectAttemptNumber % retriesPerReset == 0) { + esp_upload.state = resetting; + } + } + } + break; + + case erasing: + if (getWifiTickDiff(esp_upload.lastAttemptTime, getWifiTick()) >= blockWriteInterval) { + uint32_t eraseSize; + const uint32_t sectorsPerBlock = 16; + const uint32_t sectorSize = 4096; + const uint32_t numSectors = (esp_upload.fileSize + sectorSize - 1)/sectorSize; + const uint32_t startSector = esp_upload.uploadAddress/sectorSize; + + uint32_t headSectors = sectorsPerBlock - (startSector % sectorsPerBlock); + NOMORE(headSectors, numSectors); + + eraseSize = (numSectors < 2 * headSectors) + ? (numSectors + 1) / 2 * sectorSize + : (numSectors - headSectors) * sectorSize; + + esp_upload.uploadResult = flashBegin(esp_upload.uploadAddress, eraseSize); + if (esp_upload.uploadResult == success) { + esp_upload.uploadBlockNumber = 0; + esp_upload.uploadNextPercentToReport = percentToReportIncrement; + esp_upload.lastAttemptTime = getWifiTick(); + esp_upload.state = uploading; + } + else { + esp_upload.state = done; + } + } + break; + + case uploading: + // The ESP needs several milliseconds to recover from one packet before it will accept another + if (getWifiTickDiff(esp_upload.lastAttemptTime, getWifiTick()) >= 15) { + unsigned int percentComplete; + const uint32_t blkCnt = (esp_upload.fileSize + EspFlashBlockSize - 1) / EspFlashBlockSize; + if (esp_upload.uploadBlockNumber < blkCnt) { + esp_upload.uploadResult = flashWriteBlock(0, 0); + esp_upload.lastAttemptTime = getWifiTick(); + if (esp_upload.uploadResult != success) { + esp_upload.state = done; + } + percentComplete = (100 * esp_upload.uploadBlockNumber)/blkCnt; + ++esp_upload.uploadBlockNumber; + if (percentComplete >= esp_upload.uploadNextPercentToReport) { + esp_upload.uploadNextPercentToReport += percentToReportIncrement; + } + } + else + esp_upload.state = done; + } + break; + + case done: + update_file.close(); + esp_upload.state = upload_idle;//idle; + break; + + default: break; + } +} + +// Try to upload the given file at the given address +void SendUpdateFile(const char *file, uint32_t address) { + + const char * const fname = card.diveToFile(true, update_curDir, ESP_FIRMWARE_FILE); + if (!update_file.open(update_curDir, fname, O_READ)) return; + + esp_upload.fileSize = update_file.fileSize(); + + if (esp_upload.fileSize == 0) { + update_file.close(); + return; + } + + esp_upload.uploadAddress = address; + esp_upload.connectAttemptNumber = 0; + esp_upload.state = resetting; +} + +static const uint32_t FirmwareAddress = 0x00000000, WebFilesAddress = 0x00100000; + +void ResetWiFiForUpload(int begin_or_end) { + //#if 0 + uint32_t start, now; + + start = getWifiTick(); + now = start; + + if (begin_or_end == 0) { + SET_OUTPUT(WIFI_IO0_PIN); + WRITE(WIFI_IO0_PIN, LOW); + } + else + SET_INPUT_PULLUP(WIFI_IO0_PIN); + + WIFI_RESET(); + while (getWifiTickDiff(start, now) < 500) now = getWifiTick(); + WIFI_SET(); + //#endif +} + +int32_t wifi_upload(int type) { + esp_upload.retriesPerBaudRate = 9; + + ResetWiFiForUpload(0); + + if (type == 0) + SendUpdateFile(ESP_FIRMWARE_FILE, FirmwareAddress); + else if (type == 1) + SendUpdateFile(ESP_WEB_FIRMWARE_FILE, FirmwareAddress); + else if (type == 2) + SendUpdateFile(ESP_WEB_FILE, WebFilesAddress); + else + return -1; + + while (esp_upload.state != upload_idle) { + upload_spin(); + watchdog_refresh(); + } + + ResetWiFiForUpload(1); + + return esp_upload.uploadResult == success ? 0 : -1; +} + +#endif // HAS_TFT_LVGL_UI && MKS_WIFI_MODULE diff --git a/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.h b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.h new file mode 100644 index 0000000..ff98173 --- /dev/null +++ b/Marlin/src/lcd/extui/lib/mks_ui/wifi_upload.h @@ -0,0 +1,74 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +#ifdef __cplusplus + extern "C" { /* C-declarations for C++ */ +#endif + +#define ESP_FIRMWARE_FILE "MksWifi.bin" +#define ESP_FIRMWARE_FILE_RENAME "MKSWIFI.CUR" +#define ESP_WEB_FIRMWARE_FILE "1:/MksWifi_Web.bin" +#define ESP_WEB_FILE "1:/MksWifi_WebView.bin" + +typedef enum { + upload_idle, + resetting, + connecting, + erasing, + uploading, + done +} UploadState; + +typedef enum { + success = 0, + timeout, + connected, + badReply, + fileRead, + emptyFile, + respHeader, + slipFrame, + slipState, + slipData, +} EspUploadResult; + +typedef struct { + uint32_t fileSize; + + uint32_t uploadAddress; + UploadState state; + uint32_t retriesPerBaudRate; + uint32_t connectAttemptNumber; + uint32_t lastAttemptTime; + uint32_t lastResetTime; + uint32_t uploadBlockNumber; + uint32_t uploadNextPercentToReport; + EspUploadResult uploadResult; +} UPLOAD_STRUCT; + +extern UPLOAD_STRUCT esp_upload; +int32_t wifi_upload(int type); + +#ifdef __cplusplus + } /* C-declarations for C++ */ +#endif diff --git a/Marlin/src/lcd/extui/malyan_lcd.cpp b/Marlin/src/lcd/extui/malyan_lcd.cpp new file mode 100644 index 0000000..6c55eea --- /dev/null +++ b/Marlin/src/lcd/extui/malyan_lcd.cpp @@ -0,0 +1,543 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/** + * malyan_lcd.cpp + * + * LCD implementation for Malyan's LCD, a separate ESP8266 MCU running + * on Serial1 for the M200 board. This module outputs a pseudo-gcode + * wrapped in curly braces which the LCD implementation translates into + * actual G-code commands. + * + * Added to Marlin for Mini/Malyan M200 + * Unknown commands as of Jan 2018: {H:} + * Not currently implemented: + * {E:} when sent by LCD. Meaning unknown. + * + * Notes for connecting to boards that are not Malyan: + * The LCD is 3.3v, so if powering from a RAMPS 1.4 board or + * other 5v/12v board, use a buck converter to power the LCD and + * the 3.3v side of a logic level shifter. Aux1 on the RAMPS board + * has Serial1 and 12v, making it perfect for this. + * Copyright (c) 2017 Jason Nelson (xC0000005) + */ + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(MALYAN_LCD) + +//#define DEBUG_MALYAN_LCD + +#include "ui_api.h" + +#include "../marlinui.h" +#include "../../sd/cardreader.h" +#include "../../module/temperature.h" +#include "../../module/stepper.h" +#include "../../module/motion.h" +#include "../../libs/duration_t.h" +#include "../../module/printcounter.h" +#include "../../gcode/queue.h" + +#define DEBUG_OUT ENABLED(DEBUG_MALYAN_LCD) +#include "../../core/debug_out.h" + +// This is based on longest sys command + a filename, plus some buffer +// in case we encounter some data we don't recognize +// There is no evidence a line will ever be this long, but better safe than sorry +#define MAX_CURLY_COMMAND (32 + LONG_FILENAME_LENGTH) * 2 + +// Track incoming command bytes from the LCD +uint16_t inbound_count; + +// For sending print completion messages +bool last_printing_status = false; + +// Everything written needs the high bit set. +void write_to_lcd_P(PGM_P const message) { + char encoded_message[MAX_CURLY_COMMAND]; + uint8_t message_length = _MIN(strlen_P(message), sizeof(encoded_message)); + + LOOP_L_N(i, message_length) + encoded_message[i] = pgm_read_byte(&message[i]) | 0x80; + + LCD_SERIAL.Print::write(encoded_message, message_length); +} + +void write_to_lcd(const char * const message) { + char encoded_message[MAX_CURLY_COMMAND]; + const uint8_t message_length = _MIN(strlen(message), sizeof(encoded_message)); + + LOOP_L_N(i, message_length) + encoded_message[i] = message[i] | 0x80; + + LCD_SERIAL.Print::write(encoded_message, message_length); +} + +// {E:<msg>} is for error states. +void set_lcd_error_P(PGM_P const error, PGM_P const component=nullptr) { + write_to_lcd_P(PSTR("{E:")); + write_to_lcd_P(error); + if (component) { + write_to_lcd_P(PSTR(" ")); + write_to_lcd_P(component); + } + write_to_lcd_P(PSTR("}")); +} + + +/** + * Process an LCD 'C' command. + * These are currently all temperature commands + * {C:T0190} + * Set temp for hotend to 190 + * {C:P050} + * Set temp for bed to 50 + * + * {C:S09} set feedrate to 90 %. + * {C:S12} set feedrate to 120 %. + * + * the command portion begins after the : + */ +void process_lcd_c_command(const char* command) { + const int target_val = command[1] ? atoi(command + 1) : -1; + if (target_val < 0) { + DEBUG_ECHOLNPAIR("UNKNOWN C COMMAND ", command); + return; + } + switch (command[0]) { + case 'C': // Cope with both V1 early rev and later LCDs. + case 'S': + feedrate_percentage = target_val * 10; + LIMIT(feedrate_percentage, 10, 999); + break; + + case 'T': + // Sometimes the LCD will send commands to turn off both extruder and bed, though + // this should not happen since the printing screen is up. Better safe than sorry. + if (!print_job_timer.isRunning() || target_val > 0) + ExtUI::setTargetTemp_celsius(target_val, ExtUI::extruder_t::E0); + break; + + #if HAS_HEATED_BED + case 'P': ExtUI::setTargetTemp_celsius(target_val, ExtUI::heater_t::BED); break; + #endif + + default: DEBUG_ECHOLNPAIR("UNKNOWN C COMMAND ", command); + } +} + +/** + * Process an LCD 'B' command. + * {B:0} results in: {T0:008/195}{T1:000/000}{TP:000/000}{TQ:000C}{TT:000000} + * T0/T1 are hot end temperatures, TP is bed, TQ is percent, and TT is probably + * time remaining (HH:MM:SS). The UI can't handle displaying a second hotend, + * but the stock firmware always sends it, and it's always zero. + */ +void process_lcd_eb_command(const char* command) { + char elapsed_buffer[10]; + static uint8_t iteration = 0; + duration_t elapsed; + switch (command[0]) { + case '0': { + elapsed = print_job_timer.duration(); + sprintf_P(elapsed_buffer, PSTR("%02u%02u%02u"), uint16_t(elapsed.hour()), uint16_t(elapsed.minute()) % 60, uint16_t(elapsed.second()) % 60); + + char message_buffer[MAX_CURLY_COMMAND]; + uint8_t done_pct = print_job_timer.isRunning() ? (iteration * 10) : 100; + iteration = (iteration + 1) % 10; // Provide progress animation + #if ENABLED(SDSUPPORT) + if (ExtUI::isPrintingFromMedia() || ExtUI::isPrintingFromMediaPaused()) + done_pct = card.percentDone(); + #endif + + sprintf_P(message_buffer, + PSTR("{T0:%03i/%03i}{T1:000/000}{TP:%03i/%03i}{TQ:%03i}{TT:%s}"), + int(thermalManager.degHotend(0)), thermalManager.degTargetHotend(0), + #if HAS_HEATED_BED + int(thermalManager.degBed()), thermalManager.degTargetBed(), + #else + 0, 0, + #endif + #if ENABLED(SDSUPPORT) + done_pct, + #else + 0, + #endif + elapsed_buffer + ); + write_to_lcd(message_buffer); + } break; + + default: DEBUG_ECHOLNPAIR("UNKNOWN E/B COMMAND ", command); + } +} + +/** + * Process an LCD 'J' command. + * These are currently all movement commands. + * The command portion begins after the : + * Move X Axis + * + * {J:E}{J:X-200}{J:E} + * {J:E}{J:X+200}{J:E} + * X, Y, Z, A (extruder) + */ +template<typename T> +void j_move_axis(const char* command, const T axis) { + const float dist = atof(command + 1) / 10.0; + ExtUI::setAxisPosition_mm(ExtUI::getAxisPosition_mm(axis) + dist, axis); +}; + +void process_lcd_j_command(const char* command) { + switch (command[0]) { + case 'E': break; + case 'A': j_move_axis<ExtUI::extruder_t>(command, ExtUI::extruder_t::E0); break; + case 'Y': j_move_axis<ExtUI::axis_t>(command, ExtUI::axis_t::Y); break; + case 'Z': j_move_axis<ExtUI::axis_t>(command, ExtUI::axis_t::Z); break; + case 'X': j_move_axis<ExtUI::axis_t>(command, ExtUI::axis_t::X); break; + default: DEBUG_ECHOLNPAIR("UNKNOWN J COMMAND ", command); + } +} + +/** + * Process an LCD 'P' command, related to homing and printing. + * Cancel: + * {P:X} + * + * Home all axes: + * {P:H} + * + * Print a file: + * {P:000} + * The File number is specified as a three digit value. + * Printer responds with: + * {PRINTFILE:Mini_SNES_Bottom.gcode} + * {SYS:BUILD}echo:Now fresh file: Mini_SNES_Bottom.gcode + * File opened: Mini_SNES_Bottom.gcode Size: 5805813 + * File selected + * {SYS:BUILD} + * T:-2526.8 E:0 + * T:-2533.0 E:0 + * T:-2537.4 E:0 + * Note only the curly brace stuff matters. + */ +void process_lcd_p_command(const char* command) { + + switch (command[0]) { + case 'P': + ExtUI::pausePrint(); + write_to_lcd_P(PSTR("{SYS:PAUSED}")); + break; + case 'R': + ExtUI::resumePrint(); + write_to_lcd_P(PSTR("{SYS:RESUMED}")); + break; + case 'X': + write_to_lcd_P(PSTR("{SYS:CANCELING}")); + ExtUI::stopPrint(); + write_to_lcd_P(PSTR("{SYS:STARTED}")); + break; + case 'H': queue.enqueue_now_P(G28_STR); break; // Home all axes + default: { + #if ENABLED(SDSUPPORT) + // Print file 000 - a three digit number indicating which + // file to print in the SD card. If it's a directory, + // then switch to the directory. + + // Find the name of the file to print. + // It's needed to echo the PRINTFILE option. + // The {S:L} command should've ensured the SD card was mounted. + card.selectFileByIndex(atoi(command)); + + // There may be a difference in how V1 and V2 LCDs handle subdirectory + // prints. Investigate more. This matches the V1 motion controller actions + // but the V2 LCD switches to "print" mode on {SYS:DIR} response. + if (card.flag.filenameIsDir) { + card.cd(card.filename); + write_to_lcd_P(PSTR("{SYS:DIR}")); + } + else { + char message_buffer[MAX_CURLY_COMMAND]; + sprintf_P(message_buffer, PSTR("{PRINTFILE:%s}"), card.longest_filename()); + write_to_lcd(message_buffer); + write_to_lcd_P(PSTR("{SYS:BUILD}")); + card.openAndPrintFile(card.filename); + } + #endif + } break; // default + } // switch +} + +/** + * Handle an lcd 'S' command + * {S:I} - Temperature request + * {T0:999/000}{T1:000/000}{TP:004/000} + * + * {S:L} - File Listing request + * Printer Response: + * {FILE:buttons.gcode} + * {FILE:update.bin} + * {FILE:nupdate.bin} + * {FILE:fcupdate.flg} + * {SYS:OK} + */ +void process_lcd_s_command(const char* command) { + switch (command[0]) { + case 'I': { + // temperature information + char message_buffer[MAX_CURLY_COMMAND]; + sprintf_P(message_buffer, PSTR("{T0:%03i/%03i}{T1:000/000}{TP:%03i/%03i}"), + int(thermalManager.degHotend(0)), thermalManager.degTargetHotend(0), + #if HAS_HEATED_BED + int(thermalManager.degBed()), thermalManager.degTargetBed() + #else + 0, 0 + #endif + ); + write_to_lcd(message_buffer); + } break; + + case 'L': { + #if ENABLED(SDSUPPORT) + if (!card.isMounted()) card.mount(); + + // A more efficient way to do this would be to + // implement a callback in the ls_SerialPrint code, but + // that requires changes to the core cardreader class that + // would not benefit the majority of users. Since one can't + // select a file for printing during a print, there's + // little reason not to do it this way. + char message_buffer[MAX_CURLY_COMMAND]; + uint16_t file_count = card.get_num_Files(); + for (uint16_t i = 0; i < file_count; i++) { + card.selectFileByIndex(i); + sprintf_P(message_buffer, card.flag.filenameIsDir ? PSTR("{DIR:%s}") : PSTR("{FILE:%s}"), card.longest_filename()); + write_to_lcd(message_buffer); + } + + write_to_lcd_P(PSTR("{SYS:OK}")); + #endif + } break; + + default: DEBUG_ECHOLNPAIR("UNKNOWN S COMMAND ", command); + } +} + +/** + * Receive a curly brace command and translate to G-code. + * Currently {E:0} is not handled. Its function is unknown, + * but it occurs during the temp window after a sys build. + */ +void process_lcd_command(const char* command) { + const char *current = command; + + byte command_code = *current++; + if (*current == ':') { + + current++; // skip the : + + switch (command_code) { + case 'S': process_lcd_s_command(current); break; + case 'J': process_lcd_j_command(current); break; + case 'P': process_lcd_p_command(current); break; + case 'C': process_lcd_c_command(current); break; + case 'B': + case 'E': process_lcd_eb_command(current); break; + default: DEBUG_ECHOLNPAIR("UNKNOWN COMMAND ", command); + } + } + else + DEBUG_ECHOLNPAIR("UNKNOWN COMMAND FORMAT ", command); +} + +// +// Parse LCD commands mixed with G-Code +// +void parse_lcd_byte(const byte b) { + static char inbound_buffer[MAX_CURLY_COMMAND]; + + static uint8_t parsing = 0; // Parsing state + static bool prevcr = false; // Was the last c a CR? + + const char c = b & 0x7F; + + if (parsing) { + const bool is_lcd = parsing == 1; // 1 for LCD + if ( ( is_lcd && c == '}') // Closing brace on LCD command + || (!is_lcd && c == '\n') // LF on a G-code command + ) { + inbound_buffer[inbound_count] = '\0'; // Reset before processing + inbound_count = 0; // Reset buffer index + if (parsing == 1) + process_lcd_command(inbound_buffer); // Handle the LCD command + else + queue.enqueue_one_now(inbound_buffer); // Handle the G-code command + parsing = 0; // Unflag and... + } + else if (inbound_count < MAX_CURLY_COMMAND - 2) + inbound_buffer[inbound_count++] = is_lcd ? c : b; // Buffer while space remains + } + else { + if (c == '{') parsing = 1; // Brace opens an LCD command + else if (prevcr && c == '\n') parsing = 2; // CRLF indicates G-code + prevcr = (c == '\r'); // Remember if it was a CR + } +} + +/** + * UC means connected. + * UD means disconnected + * The stock firmware considers USB initialized as "connected." + */ +void update_usb_status(const bool forceUpdate) { + static bool last_usb_connected_status = false; + // This is mildly different than stock, which + // appears to use the usb discovery status. + // This is more logical. + if (last_usb_connected_status != MYSERIAL0.connected() || forceUpdate) { + last_usb_connected_status = MYSERIAL0.connected(); + write_to_lcd_P(last_usb_connected_status ? PSTR("{R:UC}\r\n") : PSTR("{R:UD}\r\n")); + } +} + +namespace ExtUI { + void onStartup() { + /** + * The Malyan LCD actually runs as a separate MCU on Serial 1. + * This code's job is to siphon the weird curly-brace commands from + * it and translate into ExtUI operations where possible. + */ + inbound_count = 0; + + #ifndef LCD_BAUDRATE + #define LCD_BAUDRATE 500000 + #endif + LCD_SERIAL.begin(LCD_BAUDRATE); + + // Signal init + write_to_lcd_P(PSTR("{SYS:STARTED}\r\n")); + + // send a version that says "unsupported" + write_to_lcd_P(PSTR("{VER:99}\r\n")); + + // No idea why it does this twice. + write_to_lcd_P(PSTR("{SYS:STARTED}\r\n")); + update_usb_status(true); + } + + void onIdle() { + /** + * - from printer on startup: + * {SYS:STARTED}{VER:29}{SYS:STARTED}{R:UD} + */ + + // First report USB status. + update_usb_status(false); + + // now drain commands... + while (LCD_SERIAL.available()) + parse_lcd_byte((byte)LCD_SERIAL.read()); + + #if ENABLED(SDSUPPORT) + // The way last printing status works is simple: + // The UI needs to see at least one TQ which is not 100% + // and then when the print is complete, one which is. + static uint8_t last_percent_done = 100; + + // If there was a print in progress, we need to emit the final + // print status as {TQ:100}. Reset last percent done so a new print will + // issue a percent of 0. + const uint8_t percent_done = (ExtUI::isPrinting() || ExtUI::isPrintingFromMediaPaused()) ? ExtUI::getProgress_percent() : last_printing_status ? 100 : 0; + if (percent_done != last_percent_done) { + char message_buffer[16]; + sprintf_P(message_buffer, PSTR("{TQ:%03i}"), percent_done); + write_to_lcd(message_buffer); + last_percent_done = percent_done; + last_printing_status = ExtUI::isPrinting(); + } + #endif + } + + void onPrinterKilled(PGM_P const error, PGM_P const component) { + set_lcd_error_P(error, component); + } + + #if HAS_PID_HEATING + + void onPidTuning(const result_t rst) { + // Called for temperature PID tuning result + //SERIAL_ECHOLNPAIR("OnPidTuning:", rst); + switch (rst) { + case PID_BAD_EXTRUDER_NUM: + set_lcd_error_P(GET_TEXT(MSG_PID_BAD_EXTRUDER_NUM)); + break; + case PID_TEMP_TOO_HIGH: + set_lcd_error_P(GET_TEXT(MSG_PID_TEMP_TOO_HIGH)); + break; + case PID_TUNING_TIMEOUT: + set_lcd_error_P(GET_TEXT(MSG_PID_TIMEOUT)); + break; + case PID_DONE: + set_lcd_error_P(GET_TEXT(MSG_PID_AUTOTUNE_DONE)); + break; + } + } + + #endif + + void onPrintTimerStarted() { write_to_lcd_P(PSTR("{SYS:BUILD}")); } + void onPrintTimerPaused() {} + void onPrintTimerStopped() { write_to_lcd_P(PSTR("{TQ:100}")); } + + // Not needed for Malyan LCD + void onStatusChanged(const char * const) {} + void onMediaInserted() {} + void onMediaError() {} + void onMediaRemoved() {} + void onPlayTone(const uint16_t, const uint16_t) {} + void onFilamentRunout(const extruder_t extruder) {} + void onUserConfirmRequired(const char * const) {} + void onHomingStart() {} + void onHomingComplete() {} + void onPrintFinished() {} + void onFactoryReset() {} + void onStoreSettings(char*) {} + void onLoadSettings(const char*) {} + void onConfigurationStoreWritten(bool) {} + void onConfigurationStoreRead(bool) {} + + #if HAS_MESH + void onMeshLevelingStart() {} + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval) {} + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const ExtUI::probe_state_t state) {} + #endif + + #if ENABLED(POWER_LOSS_RECOVERY) + void onPowerLossResume() {} + #endif + + void onSteppersDisabled() {} + void onSteppersEnabled() {} +} + +#endif // MALYAN_LCD diff --git a/Marlin/src/lcd/extui/ui_api.cpp b/Marlin/src/lcd/extui/ui_api.cpp new file mode 100644 index 0000000..d1ffb4c --- /dev/null +++ b/Marlin/src/lcd/extui/ui_api.cpp @@ -0,0 +1,1074 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ + +/************** + * ui_api.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../../inc/MarlinConfigPre.h" + +#if ENABLED(EXTENSIBLE_UI) + +#include "../marlinui.h" +#include "../../gcode/queue.h" +#include "../../module/motion.h" +#include "../../module/planner.h" +#include "../../module/probe.h" +#include "../../module/temperature.h" +#include "../../module/printcounter.h" +#include "../../libs/duration_t.h" +#include "../../HAL/shared/Delay.h" +#include "../../sd/cardreader.h" + +#if ENABLED(PRINTCOUNTER) + #include "../../core/utility.h" + #include "../../libs/numtostr.h" +#endif + +#if HAS_MULTI_EXTRUDER + #include "../../module/tool_change.h" +#endif + +#if ENABLED(EMERGENCY_PARSER) + #include "../../feature/e_parser.h" +#endif + +#if HAS_TRINAMIC_CONFIG + #include "../../feature/tmc_util.h" + #include "../../module/stepper/indirection.h" +#endif + +#include "ui_api.h" + +#if ENABLED(BACKLASH_GCODE) + #include "../../feature/backlash.h" +#endif + +#if HAS_LEVELING + #include "../../feature/bedlevel/bedlevel.h" +#endif + +#if HAS_FILAMENT_SENSOR + #include "../../feature/runout.h" +#endif + +#if ENABLED(CASE_LIGHT_ENABLE) + #include "../../feature/caselight.h" +#endif + +#if ENABLED(BABYSTEPPING) + #include "../../feature/babystep.h" +#endif + +#if ENABLED(HOST_PROMPT_SUPPORT) + #include "../../feature/host_actions.h" +#endif + +namespace ExtUI { + static struct { + uint8_t printer_killed : 1; + TERN_(JOYSTICK, uint8_t jogging : 1); + TERN_(SDSUPPORT, uint8_t was_sd_printing : 1); + } flags; + + #ifdef __SAM3X8E__ + /** + * Implement a special millis() to allow time measurement + * within an ISR (such as when the printer is killed). + * + * To keep proper time, must be called at least every 1s. + */ + uint32_t safe_millis() { + // Not killed? Just call millis() + if (!flags.printer_killed) return millis(); + + static uint32_t currTimeHI = 0; /* Current time */ + + // Machine was killed, reinit SysTick so we are able to compute time without ISRs + if (currTimeHI == 0) { + // Get the last time the Arduino time computed (from CMSIS) and convert it to SysTick + currTimeHI = uint32_t((GetTickCount() * uint64_t(F_CPU / 8000)) >> 24); + + // Reinit the SysTick timer to maximize its period + SysTick->LOAD = SysTick_LOAD_RELOAD_Msk; // get the full range for the systick timer + SysTick->VAL = 0; // Load the SysTick Counter Value + SysTick->CTRL = // MCLK/8 as source + // No interrupts + SysTick_CTRL_ENABLE_Msk; // Enable SysTick Timer + } + + // Check if there was a timer overflow from the last read + if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { + // There was. This means (SysTick_LOAD_RELOAD_Msk * 1000 * 8)/F_CPU ms has elapsed + currTimeHI++; + } + + // Calculate current time in milliseconds + uint32_t currTimeLO = SysTick_LOAD_RELOAD_Msk - SysTick->VAL; // (in MCLK/8) + uint64_t currTime = ((uint64_t)currTimeLO) | (((uint64_t)currTimeHI) << 24); + + // The ms count is + return (uint32_t)(currTime / (F_CPU / 8000)); + } + #endif // __SAM3X8E__ + + void delay_us(uint32_t us) { DELAY_US(us); } + + void delay_ms(uint32_t ms) { + if (flags.printer_killed) + DELAY_US(ms * 1000); + else + safe_delay(ms); + } + + void yield() { + if (!flags.printer_killed) thermalManager.manage_heater(); + } + + void enableHeater(const extruder_t extruder) { + #if HAS_HOTEND && HEATER_IDLE_HANDLER + thermalManager.reset_hotend_idle_timer(extruder - E0); + #else + UNUSED(extruder); + #endif + } + + void enableHeater(const heater_t heater) { + #if HEATER_IDLE_HANDLER + switch (heater) { + #if HAS_HEATED_BED + case BED: thermalManager.reset_bed_idle_timer(); return; + #endif + TERN_(HAS_HEATED_CHAMBER, case CHAMBER: return); // Chamber has no idle timer + default: + TERN_(HAS_HOTEND, thermalManager.reset_hotend_idle_timer(heater - H0)); + break; + } + #else + UNUSED(heater); + #endif + } + + #if ENABLED(JOYSTICK) + /** + * Jogs in the direction given by the vector (dx, dy, dz). + * The values range from -1 to 1 mapping to the maximum + * feedrate for an axis. + * + * The axis will continue to jog until this function is + * called with all zeros. + */ + void jog(const xyz_float_t &dir) { + // The "destination" variable is used as a scratchpad in + // Marlin by GCODE routines, but should remain untouched + // during manual jogging, allowing us to reuse the space + // for our direction vector. + destination = dir; + flags.jogging = !NEAR_ZERO(dir.x) || !NEAR_ZERO(dir.y) || !NEAR_ZERO(dir.z); + } + + // Called by the polling routine in "joystick.cpp" + void _joystick_update(xyz_float_t &norm_jog) { + if (flags.jogging) { + #define OUT_OF_RANGE(VALUE) (VALUE < -1.0f || VALUE > 1.0f) + + if (OUT_OF_RANGE(destination.x) || OUT_OF_RANGE(destination.y) || OUT_OF_RANGE(destination.z)) { + // If destination on any axis is out of range, it + // probably means the UI forgot to stop jogging and + // ran GCODE that wrote a position to destination. + // To prevent a disaster, stop jogging. + flags.jogging = false; + return; + } + norm_jog = destination; + } + } + #endif + + bool isHeaterIdle(const extruder_t extruder) { + #if HAS_HOTEND && HEATER_IDLE_HANDLER + return thermalManager.heater_idle[extruder - E0].timed_out; + #else + UNUSED(extruder); + return false; + #endif + } + + bool isHeaterIdle(const heater_t heater) { + #if HEATER_IDLE_HANDLER + switch (heater) { + TERN_(HAS_HEATED_BED, case BED: return thermalManager.heater_idle[thermalManager.IDLE_INDEX_BED].timed_out); + TERN_(HAS_HEATED_CHAMBER, case CHAMBER: return false); // Chamber has no idle timer + default: + return TERN0(HAS_HOTEND, thermalManager.heater_idle[heater - H0].timed_out); + } + #else + UNUSED(heater); + return false; + #endif + } + + #ifdef TOUCH_UI_LCD_TEMP_SCALING + #define GET_TEMP_ADJUSTMENT(A) (float(A) / (TOUCH_UI_LCD_TEMP_SCALING)) + #else + #define GET_TEMP_ADJUSTMENT(A) A + #endif + + float getActualTemp_celsius(const heater_t heater) { + switch (heater) { + TERN_(HAS_HEATED_BED, case BED: return GET_TEMP_ADJUSTMENT(thermalManager.degBed())); + TERN_(HAS_HEATED_CHAMBER, case CHAMBER: return GET_TEMP_ADJUSTMENT(thermalManager.degChamber())); + default: return GET_TEMP_ADJUSTMENT(thermalManager.degHotend(heater - H0)); + } + } + + float getActualTemp_celsius(const extruder_t extruder) { + return GET_TEMP_ADJUSTMENT(thermalManager.degHotend(extruder - E0)); + } + + float getTargetTemp_celsius(const heater_t heater) { + switch (heater) { + TERN_(HAS_HEATED_BED, case BED: return GET_TEMP_ADJUSTMENT(thermalManager.degTargetBed())); + TERN_(HAS_HEATED_CHAMBER, case CHAMBER: return GET_TEMP_ADJUSTMENT(thermalManager.degTargetChamber())); + default: return GET_TEMP_ADJUSTMENT(thermalManager.degTargetHotend(heater - H0)); + } + } + + float getTargetTemp_celsius(const extruder_t extruder) { + return GET_TEMP_ADJUSTMENT(thermalManager.degTargetHotend(extruder - E0)); + } + + float getTargetFan_percent(const fan_t fan) { + #if HAS_FAN + return thermalManager.fanPercent(thermalManager.fan_speed[fan - FAN0]); + #else + UNUSED(fan); + return 0; + #endif + } + + float getActualFan_percent(const fan_t fan) { + #if HAS_FAN + return thermalManager.fanPercent(thermalManager.scaledFanSpeed(fan - FAN0)); + #else + UNUSED(fan); + return 0; + #endif + } + + float getAxisPosition_mm(const axis_t axis) { + return TERN_(JOYSTICK, flags.jogging ? destination[axis] :) current_position[axis]; + } + + float getAxisPosition_mm(const extruder_t extruder) { + const extruder_t old_tool = getActiveTool(); + setActiveTool(extruder, true); + const float epos = TERN_(JOYSTICK, flags.jogging ? destination.e :) current_position.e; + setActiveTool(old_tool, true); + return epos; + } + + void setAxisPosition_mm(const float position, const axis_t axis, const feedRate_t feedrate/*=0*/) { + // Get motion limit from software endstops, if any + float min, max; + soft_endstop.get_manual_axis_limits((AxisEnum)axis, min, max); + + // Delta limits XY based on the current offset from center + // This assumes the center is 0,0 + #if ENABLED(DELTA) + if (axis != Z) { + max = SQRT(sq(float(DELTA_PRINTABLE_RADIUS)) - sq(current_position[Y - axis])); // (Y - axis) == the other axis + min = -max; + } + #endif + + current_position[axis] = constrain(position, min, max); + line_to_current_position(feedrate ?: manual_feedrate_mm_s[axis]); + } + + void setAxisPosition_mm(const float position, const extruder_t extruder, const feedRate_t feedrate/*=0*/) { + setActiveTool(extruder, true); + + current_position.e = position; + line_to_current_position(feedrate ?: manual_feedrate_mm_s.e); + } + + void setActiveTool(const extruder_t extruder, bool no_move) { + #if HAS_MULTI_EXTRUDER + const uint8_t e = extruder - E0; + if (e != active_extruder) tool_change(e, no_move); + active_extruder = e; + #else + UNUSED(extruder); + UNUSED(no_move); + #endif + } + + extruder_t getActiveTool() { + switch (active_extruder) { + case 5: return E5; + case 4: return E4; + case 3: return E3; + case 2: return E2; + case 1: return E1; + default: return E0; + } + } + + bool isMoving() { return planner.has_blocks_queued(); } + + bool canMove(const axis_t axis) { + switch (axis) { + #if IS_KINEMATIC || ENABLED(NO_MOTION_BEFORE_HOMING) + case X: return axis_should_home(X_AXIS); + case Y: return axis_should_home(Y_AXIS); + case Z: return axis_should_home(Z_AXIS); + #else + case X: case Y: case Z: return true; + #endif + default: return false; + } + } + + bool canMove(const extruder_t extruder) { + return !thermalManager.tooColdToExtrude(extruder - E0); + } + + #if HAS_SOFTWARE_ENDSTOPS + bool getSoftEndstopState() { return soft_endstop._enabled; } + void setSoftEndstopState(const bool value) { soft_endstop._enabled = value; } + #endif + + #if HAS_TRINAMIC_CONFIG + float getAxisCurrent_mA(const axis_t axis) { + switch (axis) { + #if AXIS_IS_TMC(X) + case X: return stepperX.getMilliamps(); + #endif + #if AXIS_IS_TMC(X2) + case X2: return stepperX2.getMilliamps(); + #endif + #if AXIS_IS_TMC(Y) + case Y: return stepperY.getMilliamps(); + #endif + #if AXIS_IS_TMC(Y2) + case Y2: return stepperY2.getMilliamps(); + #endif + #if AXIS_IS_TMC(Z) + case Z: return stepperZ.getMilliamps(); + #endif + #if AXIS_IS_TMC(Z2) + case Z2: return stepperZ2.getMilliamps(); + #endif + default: return NAN; + }; + } + + float getAxisCurrent_mA(const extruder_t extruder) { + switch (extruder) { + #if AXIS_IS_TMC(E0) + case E0: return stepperE0.getMilliamps(); + #endif + #if AXIS_IS_TMC(E1) + case E1: return stepperE1.getMilliamps(); + #endif + #if AXIS_IS_TMC(E2) + case E2: return stepperE2.getMilliamps(); + #endif + #if AXIS_IS_TMC(E3) + case E3: return stepperE3.getMilliamps(); + #endif + #if AXIS_IS_TMC(E4) + case E4: return stepperE4.getMilliamps(); + #endif + #if AXIS_IS_TMC(E5) + case E5: return stepperE5.getMilliamps(); + #endif + #if AXIS_IS_TMC(E6) + case E6: return stepperE6.getMilliamps(); + #endif + #if AXIS_IS_TMC(E7) + case E7: return stepperE7.getMilliamps(); + #endif + default: return NAN; + }; + } + + void setAxisCurrent_mA(const float mA, const axis_t axis) { + switch (axis) { + #if AXIS_IS_TMC(X) + case X: stepperX.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(X2) + case X2: stepperX2.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(Y) + case Y: stepperY.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(Y2) + case Y2: stepperY2.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(Z) + case Z: stepperZ.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(Z2) + case Z2: stepperZ2.rms_current(constrain(mA, 400, 1500)); break; + #endif + default: break; + }; + } + + void setAxisCurrent_mA(const float mA, const extruder_t extruder) { + switch (extruder) { + #if AXIS_IS_TMC(E0) + case E0: stepperE0.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(E1) + case E1: stepperE1.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(E2) + case E2: stepperE2.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(E3) + case E3: stepperE3.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(E4) + case E4: stepperE4.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(E5) + case E5: stepperE5.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(E6) + case E6: stepperE6.rms_current(constrain(mA, 400, 1500)); break; + #endif + #if AXIS_IS_TMC(E7) + case E7: stepperE7.rms_current(constrain(mA, 400, 1500)); break; + #endif + default: break; + }; + } + + int getTMCBumpSensitivity(const axis_t axis) { + switch (axis) { + TERN_(X_SENSORLESS, case X: return stepperX.homing_threshold()); + TERN_(X2_SENSORLESS, case X2: return stepperX2.homing_threshold()); + TERN_(Y_SENSORLESS, case Y: return stepperY.homing_threshold()); + TERN_(Y2_SENSORLESS, case Y2: return stepperY2.homing_threshold()); + TERN_(Z_SENSORLESS, case Z: return stepperZ.homing_threshold()); + TERN_(Z2_SENSORLESS, case Z2: return stepperZ2.homing_threshold()); + TERN_(Z3_SENSORLESS, case Z3: return stepperZ3.homing_threshold()); + TERN_(Z4_SENSORLESS, case Z4: return stepperZ4.homing_threshold()); + default: return 0; + } + } + + void setTMCBumpSensitivity(const float value, const axis_t axis) { + switch (axis) { + #if X_SENSORLESS || Y_SENSORLESS || Z_SENSORLESS + #if X_SENSORLESS + case X: stepperX.homing_threshold(value); break; + #endif + #if X2_SENSORLESS + case X2: stepperX2.homing_threshold(value); break; + #endif + #if Y_SENSORLESS + case Y: stepperY.homing_threshold(value); break; + #endif + #if Y2_SENSORLESS + case Y2: stepperY2.homing_threshold(value); break; + #endif + #if Z_SENSORLESS + case Z: stepperZ.homing_threshold(value); break; + #endif + #if Z2_SENSORLESS + case Z2: stepperZ2.homing_threshold(value); break; + #endif + #if Z3_SENSORLESS + case Z3: stepperZ3.homing_threshold(value); break; + #endif + #if Z4_SENSORLESS + case Z4: stepperZ4.homing_threshold(value); break; + #endif + #else + UNUSED(value); + #endif + default: break; + } + } + #endif + + float getAxisSteps_per_mm(const axis_t axis) { + return planner.settings.axis_steps_per_mm[axis]; + } + + float getAxisSteps_per_mm(const extruder_t extruder) { + UNUSED_E(extruder); + return planner.settings.axis_steps_per_mm[E_AXIS_N(extruder - E0)]; + } + + void setAxisSteps_per_mm(const float value, const axis_t axis) { + planner.settings.axis_steps_per_mm[axis] = value; + planner.refresh_positioning(); + } + + void setAxisSteps_per_mm(const float value, const extruder_t extruder) { + UNUSED_E(extruder); + planner.settings.axis_steps_per_mm[E_AXIS_N(extruder - E0)] = value; + planner.refresh_positioning(); + } + + feedRate_t getAxisMaxFeedrate_mm_s(const axis_t axis) { + return planner.settings.max_feedrate_mm_s[axis]; + } + + feedRate_t getAxisMaxFeedrate_mm_s(const extruder_t extruder) { + UNUSED_E(extruder); + return planner.settings.max_feedrate_mm_s[E_AXIS_N(extruder - E0)]; + } + + void setAxisMaxFeedrate_mm_s(const feedRate_t value, const axis_t axis) { + planner.set_max_feedrate(axis, value); + } + + void setAxisMaxFeedrate_mm_s(const feedRate_t value, const extruder_t extruder) { + UNUSED_E(extruder); + planner.set_max_feedrate(E_AXIS_N(extruder - E0), value); + } + + float getAxisMaxAcceleration_mm_s2(const axis_t axis) { + return planner.settings.max_acceleration_mm_per_s2[axis]; + } + + float getAxisMaxAcceleration_mm_s2(const extruder_t extruder) { + UNUSED_E(extruder); + return planner.settings.max_acceleration_mm_per_s2[E_AXIS_N(extruder - E0)]; + } + + void setAxisMaxAcceleration_mm_s2(const float value, const axis_t axis) { + planner.set_max_acceleration(axis, value); + planner.reset_acceleration_rates(); + } + + void setAxisMaxAcceleration_mm_s2(const float value, const extruder_t extruder) { + UNUSED_E(extruder); + planner.set_max_acceleration(E_AXIS_N(extruder - E0), value); + planner.reset_acceleration_rates(); + } + + #if HAS_FILAMENT_SENSOR + bool getFilamentRunoutEnabled() { return runout.enabled; } + void setFilamentRunoutEnabled(const bool value) { runout.enabled = value; } + bool getFilamentRunoutState() { return runout.filament_ran_out; } + void setFilamentRunoutState(const bool value) { runout.filament_ran_out = value; } + + #if HAS_FILAMENT_RUNOUT_DISTANCE + float getFilamentRunoutDistance_mm() { return runout.runout_distance(); } + void setFilamentRunoutDistance_mm(const float value) { runout.set_runout_distance(constrain(value, 0, 999)); } + #endif + #endif + + #if ENABLED(CASE_LIGHT_ENABLE) + bool getCaseLightState() { return caselight.on; } + void setCaseLightState(const bool value) { + caselight.on = value; + caselight.update_enabled(); + } + + #if CASELIGHT_USES_BRIGHTNESS + float getCaseLightBrightness_percent() { return ui8_to_percent(caselight.brightness); } + void setCaseLightBrightness_percent(const float value) { + caselight.brightness = map(constrain(value, 0, 100), 0, 100, 0, 255); + caselight.update_brightness(); + } + #endif + #endif + + #if ENABLED(LIN_ADVANCE) + float getLinearAdvance_mm_mm_s(const extruder_t extruder) { + return (extruder < EXTRUDERS) ? planner.extruder_advance_K[extruder - E0] : 0; + } + + void setLinearAdvance_mm_mm_s(const float value, const extruder_t extruder) { + if (extruder < EXTRUDERS) + planner.extruder_advance_K[extruder - E0] = constrain(value, 0, 10); + } + #endif + + #if HAS_JUNCTION_DEVIATION + + float getJunctionDeviation_mm() { + return planner.junction_deviation_mm; + } + + void setJunctionDeviation_mm(const float value) { + planner.junction_deviation_mm = constrain(value, 0.001, 0.3); + TERN_(LIN_ADVANCE, planner.recalculate_max_e_jerk()); + } + + #else + + float getAxisMaxJerk_mm_s(const axis_t axis) { + return planner.max_jerk[axis]; + } + + float getAxisMaxJerk_mm_s(const extruder_t) { + return planner.max_jerk.e; + } + + void setAxisMaxJerk_mm_s(const float value, const axis_t axis) { + planner.set_max_jerk((AxisEnum)axis, value); + } + + void setAxisMaxJerk_mm_s(const float value, const extruder_t) { + planner.set_max_jerk(E_AXIS, value); + } + #endif + + feedRate_t getFeedrate_mm_s() { return feedrate_mm_s; } + int16_t getFlowPercentage(const extruder_t extr) { return planner.flow_percentage[extr]; } + feedRate_t getMinFeedrate_mm_s() { return planner.settings.min_feedrate_mm_s; } + feedRate_t getMinTravelFeedrate_mm_s() { return planner.settings.min_travel_feedrate_mm_s; } + float getPrintingAcceleration_mm_s2() { return planner.settings.acceleration; } + float getRetractAcceleration_mm_s2() { return planner.settings.retract_acceleration; } + float getTravelAcceleration_mm_s2() { return planner.settings.travel_acceleration; } + void setFeedrate_mm_s(const feedRate_t fr) { feedrate_mm_s = fr; } + void setFlow_percent(const int16_t flow, const extruder_t extr) { planner.set_flow(extr, flow); } + void setMinFeedrate_mm_s(const feedRate_t fr) { planner.settings.min_feedrate_mm_s = fr; } + void setMinTravelFeedrate_mm_s(const feedRate_t fr) { planner.settings.min_travel_feedrate_mm_s = fr; } + void setPrintingAcceleration_mm_s2(const float acc) { planner.settings.acceleration = acc; } + void setRetractAcceleration_mm_s2(const float acc) { planner.settings.retract_acceleration = acc; } + void setTravelAcceleration_mm_s2(const float acc) { planner.settings.travel_acceleration = acc; } + + #if ENABLED(BABYSTEPPING) + bool babystepAxis_steps(const int16_t steps, const axis_t axis) { + switch (axis) { + #if ENABLED(BABYSTEP_XY) + case X: babystep.add_steps(X_AXIS, steps); break; + case Y: babystep.add_steps(Y_AXIS, steps); break; + #endif + case Z: babystep.add_steps(Z_AXIS, steps); break; + default: return false; + }; + return true; + } + + /** + * This function adjusts an axis during a print. + * + * When linked_nozzles is false, each nozzle in a multi-nozzle + * printer can be babystepped independently of the others. This + * lets the user to fine tune the Z-offset and Nozzle Offsets + * while observing the first layer of a print, regardless of + * what nozzle is printing. + */ + void smartAdjustAxis_steps(const int16_t steps, const axis_t axis, bool linked_nozzles) { + const float mm = steps * planner.steps_to_mm[axis]; + UNUSED(mm); + + if (!babystepAxis_steps(steps, axis)) return; + + #if ENABLED(BABYSTEP_ZPROBE_OFFSET) + // Make it so babystepping in Z adjusts the Z probe offset. + if (axis == Z && TERN1(HAS_MULTI_EXTRUDER, (linked_nozzles || active_extruder == 0))) + probe.offset.z += mm; + #endif + + #if HAS_MULTI_EXTRUDER && HAS_HOTEND_OFFSET + /** + * When linked_nozzles is false, as an axis is babystepped + * adjust the hotend offsets so that the other nozzles are + * unaffected by the babystepping of the active nozzle. + */ + if (!linked_nozzles) { + HOTEND_LOOP() + if (e != active_extruder) + hotend_offset[e][axis] += mm; + + normalizeNozzleOffset(X); + normalizeNozzleOffset(Y); + normalizeNozzleOffset(Z); + } + #else + UNUSED(linked_nozzles); + #endif + } + + /** + * Converts a mm displacement to a number of whole number of + * steps that is at least mm long. + */ + int16_t mmToWholeSteps(const float mm, const axis_t axis) { + const float steps = mm / planner.steps_to_mm[axis]; + return steps > 0 ? CEIL(steps) : FLOOR(steps); + } + #endif + + float getZOffset_mm() { + return (0.0f + #if HAS_BED_PROBE + + probe.offset.z + #elif ENABLED(BABYSTEP_DISPLAY_TOTAL) + + planner.steps_to_mm[Z_AXIS] * babystep.axis_total[BS_AXIS_IND(Z_AXIS)] + #endif + ); + } + + void setZOffset_mm(const float value) { + #if HAS_BED_PROBE + if (WITHIN(value, Z_PROBE_OFFSET_RANGE_MIN, Z_PROBE_OFFSET_RANGE_MAX)) + probe.offset.z = value; + #elif ENABLED(BABYSTEP_DISPLAY_TOTAL) + babystep.add_mm(Z_AXIS, value - getZOffset_mm()); + #else + UNUSED(value); + #endif + } + + #if HAS_HOTEND_OFFSET + + float getNozzleOffset_mm(const axis_t axis, const extruder_t extruder) { + if (extruder - E0 >= HOTENDS) return 0; + return hotend_offset[extruder - E0][axis]; + } + + void setNozzleOffset_mm(const float value, const axis_t axis, const extruder_t extruder) { + if (extruder - E0 >= HOTENDS) return; + hotend_offset[extruder - E0][axis] = value; + } + + /** + * The UI should call this if needs to guarantee the first + * nozzle offset is zero (such as when it doesn't allow the + * user to edit the offset the first nozzle). + */ + void normalizeNozzleOffset(const axis_t axis) { + const float offs = hotend_offset[0][axis]; + HOTEND_LOOP() hotend_offset[e][axis] -= offs; + } + + #endif // HAS_HOTEND_OFFSET + + #if HAS_BED_PROBE + float getProbeOffset_mm(const axis_t axis) { + return probe.offset.pos[axis]; + } + void setProbeOffset_mm(const float val, const axis_t axis) { + probe.offset.pos[axis] = val; + } + #endif + + #if ENABLED(BACKLASH_GCODE) + float getAxisBacklash_mm(const axis_t axis) { return backlash.distance_mm[axis]; } + void setAxisBacklash_mm(const float value, const axis_t axis) + { backlash.distance_mm[axis] = constrain(value,0,5); } + + float getBacklashCorrection_percent() { return ui8_to_percent(backlash.correction); } + void setBacklashCorrection_percent(const float value) { backlash.correction = map(constrain(value, 0, 100), 0, 100, 0, 255); } + + #ifdef BACKLASH_SMOOTHING_MM + float getBacklashSmoothing_mm() { return backlash.smoothing_mm; } + void setBacklashSmoothing_mm(const float value) { backlash.smoothing_mm = constrain(value, 0, 999); } + #endif + #endif + + uint32_t getProgress_seconds_elapsed() { + const duration_t elapsed = print_job_timer.duration(); + return elapsed.value; + } + + #if HAS_LEVELING + bool getLevelingActive() { return planner.leveling_active; } + void setLevelingActive(const bool state) { set_bed_leveling_enabled(state); } + bool getMeshValid() { return leveling_is_valid(); } + #if HAS_MESH + bed_mesh_t& getMeshArray() { return Z_VALUES_ARR; } + float getMeshPoint(const xy_uint8_t &pos) { return Z_VALUES(pos.x, pos.y); } + void setMeshPoint(const xy_uint8_t &pos, const float zoff) { + if (WITHIN(pos.x, 0, GRID_MAX_POINTS_X) && WITHIN(pos.y, 0, GRID_MAX_POINTS_Y)) { + Z_VALUES(pos.x, pos.y) = zoff; + TERN_(ABL_BILINEAR_SUBDIVISION, bed_level_virt_interpolate()); + } + } + #endif + #endif + + #if ENABLED(HOST_PROMPT_SUPPORT) + void setHostResponse(const uint8_t response) { host_response_handler(response); } + #endif + + #if ENABLED(PRINTCOUNTER) + char* getTotalPrints_str(char buffer[21]) { strcpy(buffer,i16tostr3left(print_job_timer.getStats().totalPrints)); return buffer; } + char* getFinishedPrints_str(char buffer[21]) { strcpy(buffer,i16tostr3left(print_job_timer.getStats().finishedPrints)); return buffer; } + char* getTotalPrintTime_str(char buffer[21]) { return duration_t(print_job_timer.getStats().printTime).toString(buffer); } + char* getLongestPrint_str(char buffer[21]) { return duration_t(print_job_timer.getStats().longestPrint).toString(buffer); } + char* getFilamentUsed_str(char buffer[21]) { + printStatistics stats = print_job_timer.getStats(); + sprintf_P(buffer, PSTR("%ld.%im"), long(stats.filamentUsed / 1000), int16_t(stats.filamentUsed / 100) % 10); + return buffer; + } + #endif + + float getFeedrate_percent() { return feedrate_percentage; } + + #if ENABLED(PIDTEMP) + float getPIDValues_Kp(const extruder_t tool) { return PID_PARAM(Kp, tool); } + float getPIDValues_Ki(const extruder_t tool) { return unscalePID_i(PID_PARAM(Ki, tool)); } + float getPIDValues_Kd(const extruder_t tool) { return unscalePID_d(PID_PARAM(Kd, tool)); } + + void setPIDValues(const float p, const float i, const float d, extruder_t tool) { + thermalManager.temp_hotend[tool].pid.Kp = p; + thermalManager.temp_hotend[tool].pid.Ki = scalePID_i(i); + thermalManager.temp_hotend[tool].pid.Kd = scalePID_d(d); + thermalManager.updatePID(); + } + + void startPIDTune(const float temp, extruder_t tool) { + thermalManager.PID_autotune(temp, (heater_id_t)tool, 8, true); + } + #endif + + #if ENABLED(PIDTEMPBED) + float getBedPIDValues_Kp() { return thermalManager.temp_bed.pid.Kp; } + float getBedPIDValues_Ki() { return unscalePID_i(thermalManager.temp_bed.pid.Ki); } + float getBedPIDValues_Kd() { return unscalePID_d(thermalManager.temp_bed.pid.Kd); } + + void setBedPIDValues(const float p, const float i, const float d) { + thermalManager.temp_bed.pid.Kp = p; + thermalManager.temp_bed.pid.Ki = scalePID_i(i); + thermalManager.temp_bed.pid.Kd = scalePID_d(d); + thermalManager.updatePID(); + } + + void startBedPIDTune(const float temp) { + thermalManager.PID_autotune(temp, H_BED, 4, true); + } + #endif + + void injectCommands_P(PGM_P const gcode) { queue.inject_P(gcode); } + void injectCommands(char * const gcode) { queue.inject(gcode); } + + bool commandsInQueue() { return (planner.movesplanned() || queue.has_commands_queued()); } + + bool isAxisPositionKnown(const axis_t axis) { return axis_is_trusted((AxisEnum)axis); } + bool isAxisPositionKnown(const extruder_t) { return axis_is_trusted(E_AXIS); } + bool isPositionKnown() { return all_axes_trusted(); } + bool isMachineHomed() { return all_axes_homed(); } + + PGM_P getFirmwareName_str() { + static PGMSTR(firmware_name, "Marlin " SHORT_BUILD_VERSION); + return firmware_name; + } + + void setTargetTemp_celsius(float value, const heater_t heater) { + #ifdef TOUCH_UI_LCD_TEMP_SCALING + value *= TOUCH_UI_LCD_TEMP_SCALING; + #endif + enableHeater(heater); + #if HAS_HEATED_CHAMBER + if (heater == CHAMBER) + thermalManager.setTargetChamber(LROUND(constrain(value, 0, CHAMBER_MAXTEMP - 10))); + else + #endif + #if HAS_HEATED_BED + if (heater == BED) + thermalManager.setTargetBed(LROUND(constrain(value, 0, BED_MAX_TARGET))); + else + #endif + { + #if HAS_HOTEND + const int16_t e = heater - H0; + thermalManager.setTargetHotend(LROUND(constrain(value, 0, thermalManager.heater_maxtemp[e] - HOTEND_OVERSHOOT)), e); + #endif + } + } + + void setTargetTemp_celsius(float value, const extruder_t extruder) { + #ifdef TOUCH_UI_LCD_TEMP_SCALING + value *= TOUCH_UI_LCD_TEMP_SCALING; + #endif + #if HAS_HOTEND + const int16_t e = extruder - E0; + enableHeater(extruder); + thermalManager.setTargetHotend(LROUND(constrain(value, 0, thermalManager.heater_maxtemp[e] - HOTEND_OVERSHOOT)), e); + #endif + } + + void setTargetFan_percent(const float value, const fan_t fan) { + #if HAS_FAN + if (fan < FAN_COUNT) + thermalManager.set_fan_speed(fan - FAN0, map(constrain(value, 0, 100), 0, 100, 0, 255)); + #else + UNUSED(value); + UNUSED(fan); + #endif + } + + void setFeedrate_percent(const float value) { + feedrate_percentage = constrain(value, 10, 500); + } + + bool awaitingUserConfirm() { + return wait_for_user; + } + + void setUserConfirmed() { + TERN_(HAS_RESUME_CONTINUE, wait_for_user = false); + } + + void printFile(const char *filename) { + UNUSED(filename); + IFSD(card.openAndPrintFile(filename), NOOP); + } + + bool isPrintingFromMediaPaused() { + return IFSD(isPrintingFromMedia() && !IS_SD_PRINTING(), false); + } + + bool isPrintingFromMedia() { + #if ENABLED(SDSUPPORT) + // Account for when IS_SD_PRINTING() reports the end of the + // print when there is still SD card data in the planner. + flags.was_sd_printing = card.isFileOpen() || (flags.was_sd_printing && commandsInQueue()); + return flags.was_sd_printing; + #else + return false; + #endif + } + + bool isPrinting() { + return (commandsInQueue() || isPrintingFromMedia() || IFSD(IS_SD_PRINTING(), false)) || print_job_timer.isRunning() || print_job_timer.isPaused(); + } + + bool isPrintingPaused() { + return isPrinting() && (isPrintingFromMediaPaused() || print_job_timer.isPaused()); + } + + bool isMediaInserted() { + return IFSD(IS_SD_INSERTED() && card.isMounted(), false); + } + + void pausePrint() { ui.pause_print(); } + void resumePrint() { ui.resume_print(); } + void stopPrint() { ui.abort_print(); } + + void onUserConfirmRequired_P(PGM_P const pstr) { + char msg[strlen_P(pstr) + 1]; + strcpy_P(msg, pstr); + onUserConfirmRequired(msg); + } + + void onStatusChanged_P(PGM_P const pstr) { + char msg[strlen_P(pstr) + 1]; + strcpy_P(msg, pstr); + onStatusChanged(msg); + } + + FileList::FileList() { refresh(); } + + void FileList::refresh() { num_files = 0xFFFF; } + + bool FileList::seek(const uint16_t pos, const bool skip_range_check) { + #if ENABLED(SDSUPPORT) + if (!skip_range_check && (pos + 1) > count()) return false; + card.getfilename_sorted(SD_ORDER(pos, count())); + return card.filename[0] != '\0'; + #else + UNUSED(pos); + UNUSED(skip_range_check); + return false; + #endif + } + + const char* FileList::filename() { + return IFSD(card.longest_filename(), ""); + } + + const char* FileList::shortFilename() { + return IFSD(card.filename, ""); + } + + const char* FileList::longFilename() { + return IFSD(card.longFilename, ""); + } + + bool FileList::isDir() { + return IFSD(card.flag.filenameIsDir, false); + } + + uint16_t FileList::count() { + return IFSD((num_files = (num_files == 0xFFFF ? card.get_num_Files() : num_files)), 0); + } + + bool FileList::isAtRootDir() { + return IFSD(card.flag.workDirIsRoot, true); + } + + void FileList::upDir() { + #if ENABLED(SDSUPPORT) + card.cdup(); + num_files = 0xFFFF; + #endif + } + + void FileList::changeDir(const char * const dirname) { + #if ENABLED(SDSUPPORT) + card.cd(dirname); + num_files = 0xFFFF; + #else + UNUSED(dirname); + #endif + } + +} // namespace ExtUI + +// At the moment we hook into MarlinUI methods, but this could be cleaned up in the future + +void MarlinUI::init() { ExtUI::onStartup(); } + +void MarlinUI::update() { ExtUI::onIdle(); } + +void MarlinUI::kill_screen(PGM_P const error, PGM_P const component) { + using namespace ExtUI; + if (!flags.printer_killed) { + flags.printer_killed = true; + onPrinterKilled(error, component); + } +} + +#endif // EXTENSIBLE_UI diff --git a/Marlin/src/lcd/extui/ui_api.h b/Marlin/src/lcd/extui/ui_api.h new file mode 100644 index 0000000..bfd658b --- /dev/null +++ b/Marlin/src/lcd/extui/ui_api.h @@ -0,0 +1,402 @@ +/** + * 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 <https://www.gnu.org/licenses/>. + * + */ +#pragma once + +/************ + * ui_api.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: <https://www.gnu.org/licenses/>. * + ****************************************************************************/ + +#include "../../inc/MarlinConfig.h" +#include "../marlinui.h" + +namespace ExtUI { + + // The ExtUI implementation can store up to this many bytes + // in the EEPROM when the methods onStoreSettings and + // onLoadSettings are called. + + static constexpr size_t eeprom_data_size = 48; + + enum axis_t : uint8_t { X, Y, Z, X2, Y2, Z2, Z3, Z4 }; + enum extruder_t : uint8_t { E0, E1, E2, E3, E4, E5, E6, E7 }; + enum heater_t : uint8_t { H0, H1, H2, H3, H4, H5, BED, CHAMBER }; + enum fan_t : uint8_t { FAN0, FAN1, FAN2, FAN3, FAN4, FAN5, FAN6, FAN7 }; + enum result_t : uint8_t { PID_BAD_EXTRUDER_NUM, PID_TEMP_TOO_HIGH, PID_TUNING_TIMEOUT, PID_DONE }; + + constexpr uint8_t extruderCount = EXTRUDERS; + constexpr uint8_t hotendCount = HOTENDS; + constexpr uint8_t fanCount = FAN_COUNT; + + #if HAS_MESH + typedef float bed_mesh_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y]; + #endif + + bool isMoving(); + bool isAxisPositionKnown(const axis_t); + bool isAxisPositionKnown(const extruder_t); + bool isPositionKnown(); // Axis position guaranteed, steppers active since homing + bool isMachineHomed(); // Axis position most likely correct, steppers may have deactivated + bool canMove(const axis_t); + bool canMove(const extruder_t); + void injectCommands_P(PGM_P const); + void injectCommands(char * const); + bool commandsInQueue(); + + bool isHeaterIdle(const heater_t); + bool isHeaterIdle(const extruder_t); + void enableHeater(const heater_t); + void enableHeater(const extruder_t); + + #if ENABLED(JOYSTICK) + void jog(const xyz_float_t &dir); + void _joystick_update(xyz_float_t &norm_jog); + #endif + + /** + * Getters and setters + * Should be used by the EXTENSIBLE_UI to query or change Marlin's state. + */ + PGM_P getFirmwareName_str(); + + #if HAS_SOFTWARE_ENDSTOPS + bool getSoftEndstopState(); + void setSoftEndstopState(const bool); + #endif + + #if HAS_TRINAMIC_CONFIG + float getAxisCurrent_mA(const axis_t); + float getAxisCurrent_mA(const extruder_t); + void setAxisCurrent_mA(const float, const axis_t); + void setAxisCurrent_mA(const float, const extruder_t); + + int getTMCBumpSensitivity(const axis_t); + void setTMCBumpSensitivity(const float, const axis_t); + #endif + + float getActualTemp_celsius(const heater_t); + float getActualTemp_celsius(const extruder_t); + float getTargetTemp_celsius(const heater_t); + float getTargetTemp_celsius(const extruder_t); + float getTargetFan_percent(const fan_t); + float getActualFan_percent(const fan_t); + float getAxisPosition_mm(const axis_t); + float getAxisPosition_mm(const extruder_t); + float getAxisSteps_per_mm(const axis_t); + float getAxisSteps_per_mm(const extruder_t); + feedRate_t getAxisMaxFeedrate_mm_s(const axis_t); + feedRate_t getAxisMaxFeedrate_mm_s(const extruder_t); + float getAxisMaxAcceleration_mm_s2(const axis_t); + float getAxisMaxAcceleration_mm_s2(const extruder_t); + feedRate_t getMinFeedrate_mm_s(); + feedRate_t getMinTravelFeedrate_mm_s(); + float getPrintingAcceleration_mm_s2(); + float getRetractAcceleration_mm_s2(); + float getTravelAcceleration_mm_s2(); + float getFeedrate_percent(); + int16_t getFlowPercentage(const extruder_t); + + inline uint8_t getProgress_percent() { return ui.get_progress_percent(); } + + #if HAS_PRINT_PROGRESS_PERMYRIAD + inline uint16_t getProgress_permyriad() { return ui.get_progress_permyriad(); } + #endif + + uint32_t getProgress_seconds_elapsed(); + + #if ENABLED(SHOW_REMAINING_TIME) + inline uint32_t getProgress_seconds_remaining() { return ui.get_remaining_time(); } + #endif + + #if HAS_LEVELING + bool getLevelingActive(); + void setLevelingActive(const bool); + bool getMeshValid(); + #if HAS_MESH + bed_mesh_t& getMeshArray(); + float getMeshPoint(const xy_uint8_t &pos); + void setMeshPoint(const xy_uint8_t &pos, const float zval); + void onMeshLevelingStart(); + void onMeshUpdate(const int8_t xpos, const int8_t ypos, const float zval); + inline void onMeshUpdate(const xy_int8_t &pos, const float zval) { onMeshUpdate(pos.x, pos.y, zval); } + + typedef enum : uint8_t { + MESH_START, // Prior to start of probe + MESH_FINISH, // Following probe of all points + PROBE_START, // Beginning probe of grid location + PROBE_FINISH // Finished probe of grid location + } probe_state_t; + void onMeshUpdate(const int8_t xpos, const int8_t ypos, probe_state_t state); + inline void onMeshUpdate(const xy_int8_t &pos, probe_state_t state) { onMeshUpdate(pos.x, pos.y, state); } + #endif + #endif + + #if ENABLED(HOST_PROMPT_SUPPORT) + void setHostResponse(const uint8_t); + #endif + + #if ENABLED(PRINTCOUNTER) + char* getTotalPrints_str(char buffer[21]); + char* getFinishedPrints_str(char buffer[21]); + char* getTotalPrintTime_str(char buffer[21]); + char* getLongestPrint_str(char buffer[21]); + char* getFilamentUsed_str(char buffer[21]); + #endif + + void setTargetTemp_celsius(const float, const heater_t); + void setTargetTemp_celsius(const float, const extruder_t); + void setTargetFan_percent(const float, const fan_t); + void setAxisPosition_mm(const float, const axis_t, const feedRate_t=0); + void setAxisPosition_mm(const float, const extruder_t, const feedRate_t=0); + void setAxisSteps_per_mm(const float, const axis_t); + void setAxisSteps_per_mm(const float, const extruder_t); + void setAxisMaxFeedrate_mm_s(const feedRate_t, const axis_t); + void setAxisMaxFeedrate_mm_s(const feedRate_t, const extruder_t); + void setAxisMaxAcceleration_mm_s2(const float, const axis_t); + void setAxisMaxAcceleration_mm_s2(const float, const extruder_t); + void setFeedrate_mm_s(const feedRate_t); + void setMinFeedrate_mm_s(const feedRate_t); + void setMinTravelFeedrate_mm_s(const feedRate_t); + void setPrintingAcceleration_mm_s2(const float); + void setRetractAcceleration_mm_s2(const float); + void setTravelAcceleration_mm_s2(const float); + void setFeedrate_percent(const float); + void setFlow_percent(const int16_t, const extruder_t); + bool awaitingUserConfirm(); + void setUserConfirmed(); + + #if ENABLED(LIN_ADVANCE) + float getLinearAdvance_mm_mm_s(const extruder_t); + void setLinearAdvance_mm_mm_s(const float, const extruder_t); + #endif + + #if HAS_JUNCTION_DEVIATION + float getJunctionDeviation_mm(); + void setJunctionDeviation_mm(const float); + #else + float getAxisMaxJerk_mm_s(const axis_t); + float getAxisMaxJerk_mm_s(const extruder_t); + void setAxisMaxJerk_mm_s(const float, const axis_t); + void setAxisMaxJerk_mm_s(const float, const extruder_t); + #endif + + extruder_t getActiveTool(); + void setActiveTool(const extruder_t, bool no_move); + + #if ENABLED(BABYSTEPPING) + int16_t mmToWholeSteps(const float mm, const axis_t axis); + + bool babystepAxis_steps(const int16_t steps, const axis_t axis); + void smartAdjustAxis_steps(const int16_t steps, const axis_t axis, bool linked_nozzles); + #endif + + #if HAS_HOTEND_OFFSET + float getNozzleOffset_mm(const axis_t, const extruder_t); + void setNozzleOffset_mm(const float, const axis_t, const extruder_t); + void normalizeNozzleOffset(const axis_t axis); + #endif + + float getZOffset_mm(); + void setZOffset_mm(const float); + + #if HAS_BED_PROBE + float getProbeOffset_mm(const axis_t); + void setProbeOffset_mm(const float, const axis_t); + #endif + + #if ENABLED(BACKLASH_GCODE) + float getAxisBacklash_mm(const axis_t); + void setAxisBacklash_mm(const float, const axis_t); + + float getBacklashCorrection_percent(); + void setBacklashCorrection_percent(const float); + + #ifdef BACKLASH_SMOOTHING_MM + float getBacklashSmoothing_mm(); + void setBacklashSmoothing_mm(const float); + #endif + #endif + + #if HAS_FILAMENT_SENSOR + bool getFilamentRunoutEnabled(); + void setFilamentRunoutEnabled(const bool); + bool getFilamentRunoutState(); + void setFilamentRunoutState(const bool); + + #if HAS_FILAMENT_RUNOUT_DISTANCE + float getFilamentRunoutDistance_mm(); + void setFilamentRunoutDistance_mm(const float); + #endif + #endif + + #if ENABLED(CASE_LIGHT_ENABLE) + bool getCaseLightState(); + void setCaseLightState(const bool); + + #if DISABLED(CASE_LIGHT_NO_BRIGHTNESS) + float getCaseLightBrightness_percent(); + void setCaseLightBrightness_percent(const float); + #endif + #endif + + #if ENABLED(PIDTEMP) + float getPIDValues_Kp(const extruder_t); + float getPIDValues_Ki(const extruder_t); + float getPIDValues_Kd(const extruder_t); + void setPIDValues(const float, const float, const float, extruder_t); + void startPIDTune(const float, extruder_t); + #endif + + #if ENABLED(PIDTEMPBED) + float getBedPIDValues_Kp(); + float getBedPIDValues_Ki(); + float getBedPIDValues_Kd(); + void setBedPIDValues(const float, const float, const float); + void startBedPIDTune(const float); + #endif + + /** + * Delay and timing routines + * Should be used by the EXTENSIBLE_UI to safely pause or measure time + * safe_millis must be called at least every 1 sec to guarantee time + * yield should be called within lengthy loops + */ + #ifdef __SAM3X8E__ + uint32_t safe_millis(); + #else + FORCE_INLINE uint32_t safe_millis() { return millis(); } // TODO: Implement for AVR + #endif + + void delay_us(uint32_t us); + void delay_ms(uint32_t ms); + void yield(); + + /** + * Media access routines + * + * Should be used by the EXTENSIBLE_UI to operate on files + */ + bool isMediaInserted(); + bool isPrintingFromMediaPaused(); + bool isPrintingFromMedia(); + bool isPrinting(); + bool isPrintingPaused(); + + void printFile(const char *filename); + void stopPrint(); + void pausePrint(); + void resumePrint(); + + class FileList { + private: + uint16_t num_files; + + public: + FileList(); + void refresh(); + bool seek(const uint16_t, const bool skip_range_check = false); + + const char *longFilename(); + const char *shortFilename(); + const char *filename(); + bool isDir(); + + void changeDir(const char * const dirname); + void upDir(); + bool isAtRootDir(); + uint16_t count(); + }; + + /** + * Event callback routines + * + * Should be declared by EXTENSIBLE_UI and will be called by Marlin + */ + void onStartup(); + void onIdle(); + void onMediaInserted(); + void onMediaError(); + void onMediaRemoved(); + void onPlayTone(const uint16_t frequency, const uint16_t duration); + void onPrinterKilled(PGM_P const error, PGM_P const component); + void onPrintTimerStarted(); + void onPrintTimerPaused(); + void onPrintTimerStopped(); + void onPrintFinished(); + void onFilamentRunout(const extruder_t extruder); + void onUserConfirmRequired(const char * const msg); + void onUserConfirmRequired_P(PGM_P const pstr); + void onStatusChanged(const char * const msg); + void onStatusChanged_P(PGM_P const pstr); + void onHomingStart(); + void onHomingComplete(); + void onSteppersDisabled(); + void onSteppersEnabled(); + void onFactoryReset(); + void onStoreSettings(char *); + void onLoadSettings(const char *); + void onConfigurationStoreWritten(bool success); + void onConfigurationStoreRead(bool success); + #if ENABLED(POWER_LOSS_RECOVERY) + void onPowerLossResume(); + #endif + #if HAS_PID_HEATING + void onPidTuning(const result_t rst); + #endif +}; + +/** + * Helper macros to increment or decrement a value. For example: + * + * UI_INCREMENT_BY(TargetTemp_celsius, 10, E0) + * + * Expands to: + * + * setTargetTemp_celsius(getTargetTemp_celsius(E0) + 10, E0); + * + * Or, in the case where a constant increment is desired: + * + * constexpr float increment = 10; + * + * UI_INCREMENT(TargetTemp_celsius, E0) + */ +#define UI_INCREMENT_BY(method, inc, ...) ExtUI::set ## method(ExtUI::get ## method (__VA_ARGS__) + inc, ##__VA_ARGS__) +#define UI_DECREMENT_BY(method, inc, ...) ExtUI::set ## method(ExtUI::get ## method (__VA_ARGS__) - inc, ##__VA_ARGS__) + +#define UI_INCREMENT(method, ...) UI_INCREMENT_BY(method, increment, ##__VA_ARGS__) +#define UI_DECREMENT(method, ...) UI_DECREMENT_BY(method, increment, ##__VA_ARGS__) |