diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 64187f41bf..c993bf8003 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -3244,6 +3244,11 @@ // //#define ANYCUBIC_LCD_VYPER +// +// Sovol SV-06 Resistive Touch Screen +// +//#define SOVOL_SV06_RTS + // // 320x240 Nextion 2.8" serial TFT Resistive Touch Screen NX3224T028 // diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index 740e0538bf..0cf5728110 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -79,6 +79,8 @@ #include "lcd/e3v2/creality/dwin.h" #elif ENABLED(DWIN_CREALITY_LCD_JYERSUI) #include "lcd/e3v2/jyersui/dwin.h" + #elif ENABLED(SOVOL_SV06_RTS) + #include "lcd/sovol_rts/sovol_rts.h" #endif #endif @@ -825,7 +827,11 @@ void idle(const bool no_stepper_sleep/*=false*/) { TERN_(HAS_BEEPER, buzzer.tick()); // Handle UI input / draw events - ui.update(); + #if ENABLED(SOVOL_SV06_RTS) + RTS_Update(); + #else + ui.update(); + #endif // Run i2c Position Encoders #if ENABLED(I2C_POSITION_ENCODERS) @@ -1162,6 +1168,12 @@ void setup() { millis_t serial_connect_timeout = millis() + 1000UL; while (!MYSERIAL1.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ } + #if ENABLED(SOVOL_SV06_RTS) + LCD_SERIAL.begin(BAUDRATE); + serial_connect_timeout = millis() + 1000UL; + while (!LCD_SERIAL.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ } + #endif + #if HAS_MULTI_SERIAL && !HAS_ETHERNET #ifndef BAUDRATE_2 #define BAUDRATE_2 BAUDRATE @@ -1319,8 +1331,11 @@ void setup() { // UI must be initialized before EEPROM // (because EEPROM code calls the UI). - - SETUP_RUN(ui.init()); + #if ENABLED(SOVOL_SV06_RTS) + SETUP_RUN(RTS_Update()); + #else + SETUP_RUN(ui.init()); + #endif #if PIN_EXISTS(SAFE_POWER) #if HAS_DRIVER_SAFE_POWER_PROTECT @@ -1609,6 +1624,8 @@ void setup() { #if ENABLED(DWIN_CREALITY_LCD) SETUP_RUN(dwinInitScreen()); + #elif ENABLED(SOVOL_SV06_RTS) + SETUP_RUN(rts.init()); #endif #if HAS_SERVICE_INTERVALS && DISABLED(DWIN_CREALITY_LCD) diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index 38ba0d66df..fd01e85284 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -62,6 +62,8 @@ #if ENABLED(EXTENSIBLE_UI) #include "../lcd/extui/ui_api.h" +#elif ENABLED(SOVOL_SV06_RTS) + #include "../lcd/sovol_rts/sovol_rts.h" #endif #include "../lcd/marlinui.h" @@ -150,6 +152,11 @@ static bool ensure_safe_temperature(const bool wait=true, const PauseMode mode=P ui.pause_show_message(PAUSE_MESSAGE_HEATING, mode); + #if ENABLED(SOVOL_SV06_RTS) + rts.gotoPage(ID_Cold_L, ID_Cold_D); + rts.updateTempE0(); + #endif + if (wait) return thermalManager.wait_for_hotend(active_extruder); // Allow interruption by Emergency Parser M108 @@ -277,6 +284,11 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load // "Wait for filament purge" if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_PURGE); + #if ENABLED(SOVOL_SV06_RTS) + rts.updateTempE0(); + rts.gotoPage(ID_Purge_L, ID_Purge_D); + #endif + // Extrude filament to get into hotend unscaled_e_move(purge_length, ADVANCED_PAUSE_PURGE_FEEDRATE); } @@ -292,6 +304,7 @@ bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load ui.pause_show_message(PAUSE_MESSAGE_OPTION); // MarlinUI and MKS UI also set PAUSE_RESPONSE_WAIT_FOR #else pause_menu_response = PAUSE_RESPONSE_WAIT_FOR; + TERN_(SOVOL_SV06_RTS, rts.gotoPage(ID_PurgeMore_L, ID_PurgeMore_D)); #endif while (pause_menu_response == PAUSE_RESPONSE_WAIT_FOR) idle_no_sleep(); } @@ -355,6 +368,11 @@ bool unload_filament(const_float_t unload_length, const bool show_lcd/*=false*/, if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_UNLOAD, mode); + #if ENABLED(SOVOL_SV06_RTS) + rts.updateTempE0(); + rts.gotoPage(ID_Unload_L, ID_Unload_D); + #endif + // Retract filament unscaled_e_move(-(FILAMENT_UNLOAD_PURGE_RETRACT) * mix_multiplier, (PAUSE_PARK_RETRACT_FEEDRATE) * mix_multiplier); @@ -503,6 +521,11 @@ void show_continue_prompt(const bool is_reload) { DEBUG_ECHOLNPGM("... is_reload:", is_reload); ui.pause_show_message(is_reload ? PAUSE_MESSAGE_INSERT : PAUSE_MESSAGE_WAITING); + #if ENABLED(SOVOL_SV06_RTS) + rts.updateTempE0(); + rts.gotoPage(ID_Insert_L, ID_Insert_D); + rts.sendData(Beep, SoundAddr); + #endif SERIAL_ECHO_START(); SERIAL_ECHO(is_reload ? F(_PMSG(STR_FILAMENT_CHANGE_INSERT) "\n") : F(_PMSG(STR_FILAMENT_CHANGE_WAIT) "\n")); } @@ -544,6 +567,10 @@ void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep // re-heat the nozzle, re-show the continue prompt, restart idle timers, start over if (nozzle_timed_out) { ui.pause_show_message(PAUSE_MESSAGE_HEAT); + #if ENABLED(SOVOL_SV06_RTS) + rts.updateTempE0(); + rts.gotoPage(ID_HeatNozzle_L, ID_HeatNozzle_D); + #endif SERIAL_ECHO_MSG(_PMSG(STR_FILAMENT_CHANGE_HEAT)); TERN_(HOST_PROMPT_SUPPORT, hostui.prompt_do(PROMPT_USER_CONTINUE, GET_TEXT_F(MSG_HEATER_TIMEOUT), GET_TEXT_F(MSG_REHEAT))); @@ -709,6 +736,12 @@ void resume_print( planner.set_e_position_mm((destination.e = current_position.e = resume_position.e)); ui.pause_show_message(PAUSE_MESSAGE_STATUS); + #if ENABLED(SOVOL_SV06_RTS) + if (pause_flag) + rts.gotoPage(ID_PrintResume_L, ID_PrintResume_D); + else + rts.refreshTime(); + #endif #ifdef ACTION_ON_RESUMED hostui.resumed(); diff --git a/Marlin/src/feature/powerloss.cpp b/Marlin/src/feature/powerloss.cpp index cd5fc13dda..b7dcf00385 100644 --- a/Marlin/src/feature/powerloss.cpp +++ b/Marlin/src/feature/powerloss.cpp @@ -66,6 +66,10 @@ uint32_t PrintJobRecovery::cmd_sdpos, // = 0 #include "../module/probe.h" #endif +#if ENABLED(SOVOL_SV06_RTS) + #include "../lcd/sovol_rts/sovol_rts.h" +#endif + #if ENABLED(FWRETRACT) #include "fwretract.h" #endif @@ -584,6 +588,11 @@ void PrintJobRecovery::resume() { // Resume the SD file from the last position PROCESS_SUBCOMMANDS_NOW(MString(F("M23 "), info.sd_filename)); PROCESS_SUBCOMMANDS_NOW(TS(F("M24S"), resume_sdpos, 'T', info.print_job_elapsed)); + + #if ENABLED(SOVOL_SV06_RTS) + if (rts.print_state) rts.refreshTime(); + rts.start_print_flag = false; + #endif } #if ENABLED(DEBUG_POWER_LOSS_RECOVERY) diff --git a/Marlin/src/feature/tmc_util.cpp b/Marlin/src/feature/tmc_util.cpp index a2c1207d00..63fefeb7d2 100644 --- a/Marlin/src/feature/tmc_util.cpp +++ b/Marlin/src/feature/tmc_util.cpp @@ -32,6 +32,10 @@ #include "../libs/duration_t.h" #include "../gcode/gcode.h" +#if ENABLED(SOVOL_SV06_RTS) + #include "../lcd/sovol_rts/sovol_rts.h" +#endif + #if ENABLED(TMC_DEBUG) #include "../libs/hex_print.h" #if ENABLED(MONITOR_DRIVER_STATUS) @@ -207,6 +211,7 @@ if (data.is_ot) SERIAL_ECHOLNPGM("overtemperature"); if (data.is_s2g) SERIAL_ECHOLNPGM("coil short circuit"); TERN_(TMC_DEBUG, tmc_report_all()); + TERN_(SOVOL_SV06_RTS, rts.gotoPage(ID_DriverError_L, ID_DriverError_D)); kill(F("Driver error")); } #endif diff --git a/Marlin/src/gcode/bedlevel/abl/G29.cpp b/Marlin/src/gcode/bedlevel/abl/G29.cpp index 9e85b731e1..7c8289b7de 100644 --- a/Marlin/src/gcode/bedlevel/abl/G29.cpp +++ b/Marlin/src/gcode/bedlevel/abl/G29.cpp @@ -33,6 +33,7 @@ #include "../../../module/motion.h" #include "../../../module/planner.h" #include "../../../module/probe.h" +#include "../../../module/temperature.h" #include "../../queue.h" #if ENABLED(AUTO_BED_LEVELING_LINEAR) @@ -51,6 +52,8 @@ #include "../../../lcd/extui/ui_api.h" #elif ENABLED(DWIN_CREALITY_LCD) #include "../../../lcd/e3v2/creality/dwin.h" +#elif ENABLED(SOVOL_SV06_RTS) + #include "../../../lcd/sovol_rts/sovol_rts.h" #endif #define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE) @@ -438,6 +441,12 @@ G29_TYPE GcodeSuite::G29() { remember_feedrate_scaling_off(); #if ENABLED(PREHEAT_BEFORE_LEVELING) + #if ENABLED(SOVOL_SV06_RTS) + rts.updateTempE0(); + rts.updateTempBed(); + rts.sendData(1, Wait_VP); + rts.gotoPage(ID_ABL_HeatWait_L, ID_ABL_HeatWait_D); + #endif if (!abl.dryrun) probe.preheat_for_probing(LEVELING_NOZZLE_TEMP, TERN(EXTENSIBLE_UI, ExtUI::getLevelingBedTemp(), LEVELING_BED_TEMP) ); @@ -775,6 +784,12 @@ G29_TYPE GcodeSuite::G29() { abl.z_values[abl.meshCount.x][abl.meshCount.y] = z; TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(abl.meshCount, z)); + #if ENABLED(SOVOL_SV06_RTS) + if (pt_index <= GRID_MAX_POINTS) rts.sendData(pt_index, AUTO_BED_LEVEL_ICON_VP); + rts.sendData(z * 100.0f, AUTO_BED_LEVEL_1POINT_VP + (pt_index - 1) * 2); + rts.gotoPage(ID_ABL_Wait_L, ID_ABL_Wait_D); + #endif + #endif abl.reenable = false; // Don't re-enable after modifying the mesh @@ -992,6 +1007,8 @@ G29_TYPE GcodeSuite::G29() { process_subcommands_now(F(EVENT_GCODE_AFTER_G29)); #endif + TERN_(SOVOL_SV06_RTS, RTS_AutoBedLevelPage()); + probe.use_probing_tool(false); report_current_position(); diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index e15d5d8d15..661bc2d774 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -58,6 +58,8 @@ #include "../../lcd/extui/ui_api.h" #elif ENABLED(DWIN_CREALITY_LCD) #include "../../lcd/e3v2/creality/dwin.h" +#elif ENABLED(SOVOL_SV06_RTS) + #include "../../lcd/sovol_rts/sovol_rts.h" #endif #if ENABLED(LASER_FEATURE) @@ -555,6 +557,7 @@ void GcodeSuite::G28() { ui.refresh(); + TERN_(SOVOL_SV06_RTS, RTS_MoveAxisHoming()); TERN_(DWIN_CREALITY_LCD, dwinHomingDone()); TERN_(EXTENSIBLE_UI, ExtUI::onHomingDone()); diff --git a/Marlin/src/gcode/feature/pause/G27.cpp b/Marlin/src/gcode/feature/pause/G27.cpp index 229b22a96c..99159cf66e 100644 --- a/Marlin/src/gcode/feature/pause/G27.cpp +++ b/Marlin/src/gcode/feature/pause/G27.cpp @@ -27,6 +27,9 @@ #include "../../gcode.h" #include "../../../libs/nozzle.h" #include "../../../module/motion.h" +#if ENABLED(SOVOL_SV06_RTS) + #include "../../../lcd/sovol_rts/sovol_rts.h" +#endif /** * G27: Park the nozzle according with the given style @@ -42,6 +45,7 @@ void GcodeSuite::G27() { // Don't allow nozzle parking without homing first if (homing_needed_error()) return; nozzle.park(parser.ushortval('P')); + TERN_(SOVOL_SV06_RTS, RTS_MoveAxisHoming()); } #endif // NOZZLE_PARK_FEATURE diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp index a87f14c258..293179ba6f 100644 --- a/Marlin/src/gcode/feature/pause/M600.cpp +++ b/Marlin/src/gcode/feature/pause/M600.cpp @@ -28,7 +28,11 @@ #include "../../../feature/pause.h" #include "../../../module/motion.h" #include "../../../module/printcounter.h" + #include "../../../lcd/marlinui.h" +#if ENABLED(SOVOL_SV06_RTS) + #include "../../../lcd/sovol_rts/sovol_rts.h" +#endif #if HAS_MULTI_EXTRUDER #include "../../../module/tool_change.h" @@ -115,6 +119,8 @@ void GcodeSuite::M600() { if (standardM600) ui.pause_show_message(PAUSE_MESSAGE_CHANGING, PAUSE_MODE_PAUSE_PRINT, target_extruder); + TERN_(SOVOL_SV06_RTS, rts.gotoPage(ID_ChangeWait_L, ID_ChangeWait_D)); //given the context it seems this likely should have been pages 6 & 61 + // If needed, home before parking for filament change TERN_(HOME_BEFORE_FILAMENT_CHANGE, home_if_needed(true)); diff --git a/Marlin/src/gcode/motion/G0_G1.cpp b/Marlin/src/gcode/motion/G0_G1.cpp index 957541a361..c6c1833806 100644 --- a/Marlin/src/gcode/motion/G0_G1.cpp +++ b/Marlin/src/gcode/motion/G0_G1.cpp @@ -35,6 +35,10 @@ #include "../../module/planner.h" #endif +#if ENABLED(SOVOL_SV06_RTS) + #include "../../lcd/sovol_rts/sovol_rts.h" +#endif + extern xyze_pos_t destination; #if ENABLED(VARIABLE_G0_FEEDRATE) @@ -116,4 +120,6 @@ void GcodeSuite::G0_G1(TERN_(HAS_FAST_MOVES, const bool fast_move/*=false*/)) { #else TERN_(FULL_REPORT_TO_HOST_FEATURE, report_current_grblstate_moving()); #endif + + TERN_(SOVOL_SV06_RTS, RTS_PauseMoveAxisPage()); } diff --git a/Marlin/src/gcode/sd/M1001.cpp b/Marlin/src/gcode/sd/M1001.cpp index a00ca61228..a8213f3fa1 100644 --- a/Marlin/src/gcode/sd/M1001.cpp +++ b/Marlin/src/gcode/sd/M1001.cpp @@ -59,6 +59,10 @@ #define PE_LEDS_COMPLETED_TIME (30*60) #endif +#if ENABLED(SOVOL_SV06_RTS) + #include "../../lcd/sovol_rts/sovol_rts.h" +#endif + /** * M1001: Execute actions for SD print completion */ @@ -110,6 +114,14 @@ void GcodeSuite::M1001() { // Re-select the last printed file in the UI TERN_(SD_REPRINT_LAST_SELECTED_FILE, ui.reselect_last_file()); + + #if ENABLED(SOVOL_SV06_RTS) + rts.sendData(100, PRINT_PROCESS_VP); delay(1); + rts.sendData(100, PRINT_PROCESS_ICON_VP); delay(1); + rts.sendData(0, PRINT_SURPLUS_TIME_HOUR_VP); delay(1); + rts.sendData(0, PRINT_SURPLUS_TIME_MIN_VP); delay(1); + rts.gotoPage(ID_Finish_L, ID_Finish_D); + #endif } #endif // HAS_MEDIA diff --git a/Marlin/src/inc/Conditionals-2-LCD.h b/Marlin/src/inc/Conditionals-2-LCD.h index cc01e93aa7..17f89e5491 100644 --- a/Marlin/src/inc/Conditionals-2-LCD.h +++ b/Marlin/src/inc/Conditionals-2-LCD.h @@ -483,7 +483,7 @@ #if ANY(DWIN_CREALITY_LCD, DWIN_LCD_PROUI) #define HAS_DWIN_E3V2_BASIC 1 #endif -#if ANY(HAS_DWIN_E3V2_BASIC, DWIN_CREALITY_LCD_JYERSUI) +#if ANY(HAS_DWIN_E3V2_BASIC, DWIN_CREALITY_LCD_JYERSUI, SOVOL_SV06_RTS) #define HAS_DWIN_E3V2 1 #define STD_ENCODER_PULSES_PER_STEP 4 #endif @@ -555,7 +555,7 @@ #endif // E3V2 extras -#if HAS_DWIN_E3V2 || IS_DWIN_MARLINUI +#if ANY(HAS_DWIN_E3V2, IS_DWIN_MARLINUI, SOVOL_SV06_RTS) #define SERIAL_CATCHALL 0 #define HAS_LCD_BRIGHTNESS 1 #define LCD_BRIGHTNESS_MAX 250 @@ -568,7 +568,7 @@ #endif // Serial Controllers require LCD_SERIAL_PORT -#if ANY(IS_DWIN_MARLINUI, HAS_DWIN_E3V2, HAS_DGUS_LCD, MALYAN_LCD, ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON, NEXTION_TFT) +#if ANY(IS_DWIN_MARLINUI, HAS_DWIN_E3V2, HAS_DGUS_LCD, MALYAN_LCD, ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON, NEXTION_TFT, SOVOL_SV06_RTS) #define LCD_IS_SERIAL_HOST 1 #endif diff --git a/Marlin/src/inc/Conditionals-5-post.h b/Marlin/src/inc/Conditionals-5-post.h index df6efb1ed6..4884d7df0a 100644 --- a/Marlin/src/inc/Conditionals-5-post.h +++ b/Marlin/src/inc/Conditionals-5-post.h @@ -3225,7 +3225,7 @@ * Advanced Pause - Filament Change */ #if ENABLED(ADVANCED_PAUSE_FEATURE) - #if ANY(HAS_MARLINUI_MENU, EXTENSIBLE_UI, DWIN_CREALITY_LCD_JYERSUI) || ALL(EMERGENCY_PARSER, HOST_PROMPT_SUPPORT) + #if ANY(HAS_MARLINUI_MENU, EXTENSIBLE_UI, DWIN_CREALITY_LCD_JYERSUI, SOVOL_SV06_RTS) || ALL(EMERGENCY_PARSER, HOST_PROMPT_SUPPORT) #define M600_PURGE_MORE_RESUMABLE 1 // UI provides some way to Purge More / Resume #endif #ifndef FILAMENT_CHANGE_SLOW_LOAD_LENGTH diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 42d63ee398..5f7be17b9b 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -2736,7 +2736,7 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i + COUNT_ENABLED(ANYCUBIC_LCD_I3MEGA, ANYCUBIC_LCD_CHIRON, ANYCUBIC_TFT35, ANYCUBIC_LCD_VYPER) \ + DGUS_UI_IS(ORIGIN) + DGUS_UI_IS(FYSETC) + DGUS_UI_IS(HIPRECY) + DGUS_UI_IS(MKS) + DGUS_UI_IS(RELOADED) + DGUS_UI_IS(IA_CREALITY) \ + COUNT_ENABLED(ENDER2_STOCKDISPLAY, CR10_STOCKDISPLAY) \ - + COUNT_ENABLED(DWIN_CREALITY_LCD, DWIN_LCD_PROUI, DWIN_CREALITY_LCD_JYERSUI, DWIN_MARLINUI_PORTRAIT, DWIN_MARLINUI_LANDSCAPE) \ + + COUNT_ENABLED(DWIN_CREALITY_LCD, DWIN_LCD_PROUI, DWIN_CREALITY_LCD_JYERSUI, DWIN_MARLINUI_PORTRAIT, DWIN_MARLINUI_LANDSCAPE, SOVOL_SV06_RTS) \ + COUNT_ENABLED(FYSETC_MINI_12864_X_X, FYSETC_MINI_12864_1_2, FYSETC_MINI_12864_2_0, FYSETC_GENERIC_12864_1_1) \ + COUNT_ENABLED(LCD_SAINSMART_I2C_1602, LCD_SAINSMART_I2C_2004) \ + COUNT_ENABLED(MKS_12864OLED, MKS_12864OLED_SSD1306) \ diff --git a/Marlin/src/lcd/marlinui.cpp b/Marlin/src/lcd/marlinui.cpp index d618440cb2..b8e11b5b4d 100644 --- a/Marlin/src/lcd/marlinui.cpp +++ b/Marlin/src/lcd/marlinui.cpp @@ -50,6 +50,8 @@ MarlinUI ui; #include "e3v2/creality/dwin.h" #elif ENABLED(DWIN_CREALITY_LCD_JYERSUI) #include "e3v2/jyersui/dwin.h" +#elif ENABLED(SOVOL_SV06_RTS) + #include "sovol_rts/sovol_rts.h" #endif #if ENABLED(LCD_PROGRESS_BAR) && !IS_TFTGLCD_PANEL @@ -117,7 +119,9 @@ constexpr uint8_t epps = ENCODER_PULSES_PER_STEP; void MarlinUI::set_brightness(const uint8_t value) { backlight = !!value; if (backlight) brightness = constrain(value, LCD_BRIGHTNESS_MIN, LCD_BRIGHTNESS_MAX); - _set_brightness(); + #if DISABLED(SOVOL_SV06_RTS) + _set_brightness(); + #endif } #endif diff --git a/Marlin/src/lcd/sovol_rts/sovol_rts.cpp b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp new file mode 100644 index 0000000000..89e229d7d5 --- /dev/null +++ b/Marlin/src/lcd/sovol_rts/sovol_rts.cpp @@ -0,0 +1,1775 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#include "../../inc/MarlinConfig.h" + +#if ENABLED(SOVOL_SV06_RTS) + +#include "sovol_rts.h" + +DB RTS::recdat; +DB RTS::snddat; +uint8_t RTS::databuf[DATA_BUF_SIZE]; + +uint8_t RTS::print_state = 0; +bool RTS::start_print_flag = false; +bool RTS::dark_mode = false; + +RTS rts; + +#include +#include +#include +#include "../../MarlinCore.h" +#include "../../core/serial.h" +#include "../../core/macros.h" +#include "../../sd/cardreader.h" +#include "../../module/temperature.h" +#include "../../module/planner.h" +#include "../../module/stepper.h" +#include "../../module/settings.h" +#include "../../module/motion.h" +#include "../../module/printcounter.h" +#include "../../libs/duration_t.h" +#include "../../feature/babystep.h" +#include "../../feature/powerloss.h" +#include "../../feature/bedlevel/bedlevel.h" +#include "../../feature/tmc_util.h" +#include "../../gcode/queue.h" +#include "../../gcode/gcode.h" +//#include "../marlinui.h" +//#include "../utf8.h" +#include "../../libs/BL24CXX.h" + +#if ENABLED(FIX_MOUNTED_PROBE) + #include "../../module/endstops.h" +#endif +#if HAS_BED_PROBE + #include "../../module/probe.h" +#endif + +#if HAS_FILAMENT_SENSOR + //#define CHECKFILAMENT + #include "../../feature/runout.h" +#endif + +float zprobe_zoffset; +float last_zoffset = 0.0; + +int16_t startprogress = 0; +CRec cardRec; +bool sdcard_pause_check = true; + +float change_filament_temp_0 = 200; + +int16_t heatway = 0; +millis_t next_rts_update_ms = 0; + +int8_t waitway = 0; +int16_t recnum = 0; + +uint8_t job_percent = 0; + +bool pause_action_flag = false; +bool pause_flag = false; +bool power_off_type_yes = false; + +bool update_sd = false; // Flag to update the file list + +#if HAS_HOTEND + int16_t last_target_temperature[1] = { 0 }; +#endif +#if HAS_HEATED_BED + int16_t last_target_temperature_bed; +#endif + +bool lcd_sd_status; // SD-card status. true = SD available + +int16_t FilenamesCount = 0; +char cmdbuf[20] = { 0 }; +float filament_load_0 = 10.0f; +float XoffsetValue; + +// 0 for 10mm, 1 for 1mm, 2 for 0.1mm +uint8_t AxisUnitMode; +float axis_unit = 10; +int16_t update_time_value = 0; + +bool poweroff_continue = false; +char commandbuf[30]; + +static SovolPage change_page_number = ID_Startup; + +uint16_t remain_time = 0; + +static bool last_card_insert_st; +bool card_insert_st; +bool sd_printing; + +int16_t fan_speed; +char cmd[MAX_CMD_SIZE + 16]; + +inline void RTS_line_to_current(const AxisEnum axis) { + if (!planner.is_full()) + planner.buffer_line(current_position, MMM_TO_MMS(manual_feedrate_mm_m[axis]), active_extruder); +} + +RTS::RTS() { + recdat.head[0] = snddat.head[0] = FHONE; + recdat.head[1] = snddat.head[1] = FHTWO; + ZERO(databuf); +} + +void RTS::sdCardInit() { + if (sdDetected()) card.mount(); + if (card.flag.mounted) { + const int16_t fileCnt = card.get_num_items(); + card.getWorkDirName(); + if (card.filename[0] != '/') card.cdup(); + + int16_t addrnum = 0, num = 0; + for (uint16_t i = 0; i < fileCnt && i < (MAX_NUM_FILES) + addrnum; i++) { + card.selectFileByIndex(fileCnt - 1 - i); + char * const pFilename = card.longest_filename(); + const int16_t filenamelen = strlen(pFilename); + int16_t j = 1; + while (strncmp(&pFilename[j], ".gco", 4) && strncmp(&pFilename[j], ".GCO", 4) && j++ < filenamelen); + if (j >= filenamelen) { addrnum++; continue; } + + if (j >= FILENAME_LEN) { + strncpy(&pFilename[FILENAME_LEN - 3], "..", 2); + pFilename[FILENAME_LEN - 1] = '\0'; + j = FILENAME_LEN - 1; + } + + strncpy(cardRec.display_filename[num], pFilename, j); + + strcpy(cardRec.filename[num], card.filename); + cardRec.addr[num] = FILE1_TEXT_VP + (num * 20); + sendData(cardRec.display_filename[num], cardRec.addr[num]); + cardRec.Filesum = (++num); + } + for (uint16_t j = cardRec.Filesum; j < MAX_NUM_FILES; j++) { + cardRec.addr[j] = FILE1_TEXT_VP + (j * 20); + sendData(0, cardRec.addr[j]); + } + for (uint8_t j = 0; j < 20; j++) { + // Clear the file name displayed in the print interface + sendData(0, PRINT_FILE_TEXT_VP + j); + } + lcd_sd_status = IS_SD_INSERTED(); + } + else { + // Clean all filename Icons + for (uint8_t j = 0; j < MAX_NUM_FILES; j++) + for (uint8_t i = 0; i < FILENAME_LEN; i++) + sendData(0, cardRec.addr[j] + i); + ZERO(&cardRec); + } +} + +bool RTS::sdDetected() { + static bool state = false, stable = false, was_present = false; + static millis_t stable_ms = 0; + + const bool present = IS_SD_INSERTED(); + if (present != was_present) + stable = false; + else if (!stable) { + stable = true; + stable_ms = millis() + 30; + } + + if (stable && ELAPSED(millis(), stable_ms)) + state = present; + + was_present = present; + return state; +} + +void RTS::sdCardUpdate() { + const bool sd_status = sdDetected(); + if (sd_status != lcd_sd_status) { + if (sd_status) { + // SD card power on + card.mount(); + sdCardInit(); + } + else { + card.release(); + + for (uint8_t i = 0; i < cardRec.Filesum; i++) { + for (uint8_t j = 0; j < 20; j++) sendData(0, cardRec.addr[i] + j); + sendData(uint32_t(0x738E), FilenameNature + (i + 1) * 16); + } + + // Clean screen + for (uint8_t j = 0; j < 20; j++) { + sendData(0, PRINT_FILE_TEXT_VP + j); + sendData(0, SELECT_FILE_TEXT_VP + j); + } + ZERO(&cardRec); + } + lcd_sd_status = sd_status; + } + + // Represents to update file list + if (update_sd && lcd_sd_status && sdDetected()) { + for (uint16_t i = 0; i < cardRec.Filesum; i++) { + delay(1); + sendData(cardRec.display_filename[i], cardRec.addr[i]); + sendData(uint32_t(0x738E), FilenameNature + (i + 1) * 16); + } + update_sd = false; + } +} + +void RTS::init() { + dark_mode = BL24CXX::readOneByte(FONT_EEPROM); + AxisUnitMode = 1; + #if ENABLED(AUTO_BED_LEVELING_BILINEAR) + bool zig = false; + int8_t inStart, inStop, inInc, showcount; + showcount = 0; + for (int8_t y = 0; y < GRID_MAX_POINTS_Y; y++) { + // Away from origin + if (zig) { + inStart = 0; + inStop = GRID_MAX_POINTS_X; + inInc = 1; + } + else { + // Towards origin + inStart = GRID_MAX_POINTS_X - 1; + inStop = -1; + inInc = -1; + } + zig ^= true; + for (int8_t x = inStart; x != inStop; x += inInc) { + sendData(bedlevel.z_values[x][y] * 100, AUTO_BED_LEVEL_1POINT_VP + showcount * 2); + showcount++; + } + } + queue.enqueue_now(F("M420 S1")); + #endif + last_zoffset = zprobe_zoffset = probe.offset.z; + sendData(probe.offset.z * 100, AUTO_BED_LEVEL_ZOFFSET_VP); + + TERN_(HAS_HOTEND, last_target_temperature[0] = thermalManager.degTargetHotend(0)); + TERN_(HAS_HEATED_BED, last_target_temperature_bed = thermalManager.degTargetBed()); + + feedrate_percentage = 100; + sendData(feedrate_percentage, PRINT_SPEED_RATE_VP); + + /***************turn off motor*****************/ + sendData(1, MOTOR_FREE_ICON_VP); + + /***************transmit temperature to screen*****************/ + updateTempE0(); + updateTempBed(); + + /***************transmit Fan speed to screen*****************/ + // Turn off fans + thermalManager.zero_fan_speeds(); + //queue.enqueue_now(F("M107")); + //sendData(1, HEAD0_FAN_ICON_VP); + updateFan0(); + + delay(5); + + /*********transmit SD card filename to screen***************/ + sdCardInit(); + + /**************************some info init*******************************/ + sendData(0, PRINT_PROCESS_ICON_VP); + change_page_number = card.flag.mounted ? (dark_mode ? ID_Home_D : ID_Home_L) : ID_Startup; +} + +int16_t RTS::receiveData() { + int16_t frame_index = 0, timeout = 0, framelen = 0; + bool frame_flag = false; + if (LCD_SERIAL.available() <= 0) return -1; + do { + if (LCD_SERIAL.available() > 0) { + databuf[frame_index] = LCD_SERIAL.read(); + timeout = 0; + // 0x5A + if (frame_index == 0 && databuf[frame_index] == FHONE) { + frame_index++; + continue; + } + // 0xA5 + else if (frame_index == 1) { + if (databuf[frame_index] == FHTWO) frame_index++; else frame_index = 0; + continue; + } + // 长度 + else if (frame_index == 2) { + framelen = databuf[frame_index]; + frame_index++; + continue; + } + else if (frame_index != 0) { + frame_index++; + // After a frame of data is extracted, the remaining serial data will be processed next time the function will be processed + if (frame_index == (framelen + 3)) { + frame_flag = true; + break; + } + } + } + else { + timeout++; + delay(1); + } + } while (timeout < 50); // Timeout function + + if (frame_flag) { + recdat.head[0] = databuf[0]; + recdat.head[1] = databuf[1]; + recdat.len = databuf[2]; + recdat.command = databuf[3]; + for (uint8_t idx = 0; idx < frame_index; idx++) { } + } + else + return -1; + + // Response for writing byte + if (recdat.len == 0x03 + && (recdat.command == 0x82 || recdat.command == 0x80) + && databuf[4] == 0x4F && databuf[5] == 0x4B + ) { + ZERO(databuf); + recnum = 0; + return -1; + } + else if (recdat.command == 0x83) { + // Response for reading the data from the variate + recdat.addr = databuf[4]; + recdat.addr = (recdat.addr << 8) | databuf[5]; + recdat.bytelen = databuf[6]; + for (uint16_t i = 0; i < recdat.bytelen; i += 2) { + recdat.data[i / 2] = databuf[7 + i]; + recdat.data[i / 2] = (recdat.data[i / 2] << 8) | databuf[8 + i]; + } + } + else if (recdat.command == 0x81) { + // Response for reading the page from the register + recdat.addr = databuf[4]; + recdat.bytelen = databuf[5]; + for (uint16_t i = 0; i < recdat.bytelen; i++) { + recdat.data[i] = databuf[6 + i]; + //recdat.data[i] = (recdat.data[i] << 8 )| databuf[7 + i]; + } + } + else { + ZERO(databuf); + recnum = 0; + // Receive the wrong data + return -1; + } + ZERO(databuf); + recnum = 0; + + return 2; +} + +void RTS::sendData() { + if (snddat.head[0] == FHONE && snddat.head[1] == FHTWO && snddat.len >= 3) { + databuf[0] = snddat.head[0]; + databuf[1] = snddat.head[1]; + databuf[2] = snddat.len; + databuf[3] = snddat.command; + // To write data to the register + if (snddat.command == 0x80) { + databuf[4] = snddat.addr; + for (uint16_t i = 0; i < snddat.len - 2; i++) + databuf[5 + i] = snddat.data[i]; + } + else if (snddat.len == 3 && snddat.command == 0x81) { + // To read data from the register + databuf[4] = snddat.addr; + databuf[5] = snddat.bytelen; + } + else if (snddat.command == 0x82) { + // To write data to the variate + databuf[4] = snddat.addr >> 8; + databuf[5] = snddat.addr & 0xFF; + for (uint16_t i = 0; i < snddat.len - 3; i += 2) { + databuf[6 + i] = snddat.data[i/2] >> 8; + databuf[7 + i] = snddat.data[i/2] & 0xFF; + } + } + else if (snddat.len == 4 && snddat.command == 0x83) { + // To read data from the variate + databuf[4] = snddat.addr >> 8; + databuf[5] = snddat.addr & 0xFF; + databuf[6] = snddat.bytelen; + } + for (uint16_t i = 0; i < snddat.len + 3; i++) + LCD_SERIAL.write(databuf[i]); + + ZERO(&snddat); + ZERO(databuf); + snddat.head[0] = FHONE; + snddat.head[1] = FHTWO; + } +} + +void RTS::sendData(const String &s, const uint32_t addr, const uint8_t cmd/*=VarAddr_W*/) { + if (s.length() < 1) return; + sendData(s.c_str(), addr, cmd); +} + +void RTS::sendData(const char str[], const uint32_t addr, const uint8_t cmd/*=VarAddr_W*/) { + int16_t len = strlen(str); + if (len > 0) { + databuf[0] = FHONE; + databuf[1] = FHTWO; + databuf[2] = 3 + len; + databuf[3] = cmd; + databuf[4] = addr >> 8; + databuf[5] = addr & 0x00FF; + for (int16_t i = 0; i < len; i++) databuf[6 + i] = str[i]; + for (int16_t i = 0; i < len + 6; i++) LCD_SERIAL.write(databuf[i]); + ZERO(databuf); + } +} + +void RTS::sendData(const char c, const uint32_t addr, const uint8_t cmd/*=VarAddr_W*/) { + snddat.command = cmd; + snddat.addr = addr; + snddat.data[0] = uint32_t(c); + snddat.data[0] = snddat.data[0] << 8; + snddat.len = 5; + sendData(); +} + +void RTS::sendData(const int16_t n, const uint32_t addr, const uint8_t cmd/*=VarAddr_W*/) { + if (cmd == VarAddr_W) { + if (n > 0xFFFF) { + snddat.data[0] = n >> 16; + snddat.data[1] = n & 0xFFFF; + snddat.len = 7; + } + else { + snddat.data[0] = n; + snddat.len = 5; + } + } + else if (cmd == RegAddr_W) { + snddat.data[0] = n; + snddat.len = 3; + } + else if (cmd == VarAddr_R) { + snddat.bytelen = n; + snddat.len = 4; + } + snddat.command = cmd; + snddat.addr = addr; + sendData(); +} + +void RTS::sendData(const uint32_t n, const uint32_t addr, const uint8_t cmd/*=VarAddr_W*/) { + if (cmd == VarAddr_W) { + if (n > 0xFFFF) { + snddat.data[0] = n >> 16; + snddat.data[1] = n & 0xFFFF; + snddat.len = 7; + } + else { + snddat.data[0] = n; + snddat.len = 5; + } + } + else if (cmd == VarAddr_R) { + snddat.bytelen = n; + snddat.len = 4; + } + snddat.command = cmd; + snddat.addr = addr; + sendData(); +} + +void RTS::sdCardStop() { + waitway = 7; + change_page_number = ID_Home_D; + card.flag.abort_sd_printing = true; + + IF_DISABLED(SD_ABORT_NO_COOLDOWN, thermalManager.disable_all_heaters()); + print_job_timer.reset(); + + thermalManager.setTargetHotend(0, 0); + thermalManager.setTargetBed(0); + updateTempE0(); + updateTempBed(); + thermalManager.zero_fan_speeds(); + wait_for_heatup = wait_for_user = false; + poweroff_continue = false; + #if ALL(SDSUPPORT, POWER_LOSS_RECOVERY) + if (card.flag.mounted) card.removeJobRecoveryFile(); + #endif + #ifdef EVENT_GCODE_SD_STOP + queue.inject(F(EVENT_GCODE_SD_STOP)); + #endif + + // Shut down the stepper motor. + //queue.enqueue_now(F("M84")); + sendData(0, MOTOR_FREE_ICON_VP); + + sendData(0, PRINT_PROCESS_ICON_VP); + sendData(0, PRINT_PROCESS_VP); + delay(2); + for (uint8_t j = 0; j < 20; j++) { + sendData(0, PRINT_FILE_TEXT_VP + j); // Clean screen + sendData(0, SELECT_FILE_TEXT_VP + j); // Clean filename + } +} + +void RTS::handleData() { + int16_t checkKey = -1; + // For waiting + if (waitway > 0) { + memset(&recdat, 0, sizeof(recdat)); + recdat.head[0] = FHONE; + recdat.head[1] = FHTWO; + return; + } + for (uint16_t i = 0; Addrbuf[i] != 0; i++) { + if (recdat.addr == Addrbuf[i]) { + if (Addrbuf[i] >= ChangePageKey) checkKey = i; + break; + } + } + + if (checkKey < 0) { + ZERO(&recdat); + recdat.head[0] = FHONE; + recdat.head[1] = FHTWO; + return; + } + + switch (checkKey) { + case MainPageKey: // Front page + if (recdat.data[0] == 1) { // Select print file + update_sd = true; + cardRec.recordcount = -1; + if (card.flag.mounted) { + for (uint8_t j = 0; j < 20; j++) sendData(0, SELECT_FILE_TEXT_VP + j); + gotoPage(ID_Page1_L, ID_Page1_D); + } + else + gotoPage(ID_BrowseNoSd_L, ID_BrowseNoSd_D); + } + else if (recdat.data[0] == 2) { // Complete printing + waitway = 7; + card.flag.abort_sd_printing = true; + quickstop_stepper(); + print_job_timer.reset(); + queue.clear(); + sendData(0, MOTOR_FREE_ICON_VP); + sendData(0, PRINT_PROCESS_ICON_VP); + sendData(0, PRINT_PROCESS_VP); + delay(2); + sendData(0, PRINT_TIME_HOUR_VP); + sendData(0, PRINT_TIME_MIN_VP); + sendData(0, PRINT_SURPLUS_TIME_HOUR_VP); + sendData(0, PRINT_SURPLUS_TIME_MIN_VP); + + change_page_number = ID_Home_D; + } + else if (recdat.data[0] == 3) { // Enter the tone interface + waitway = 6; + queue.enqueue_now(F("G28\nG1 F200 Z0.0")); + updateFan0(); + sendData(1, Wait_VP); + gotoPage(ID_AutoHome_L, ID_AutoHome_D); + } + else if (recdat.data[0] == 4) { // Enter the settings interface + gotoPage(ID_Settings_L, ID_Settings_D); + } + else if (recdat.data[0] == 5) { // Enter the temperature interface + updateFan0(); + gotoPage(ID_TempChange_L, ID_TempChange_D); + } + else if (recdat.data[0] == 6) { // Light mode + dark_mode = false; + BL24CXX::writeOneByte(FONT_EEPROM, dark_mode); + gotoPage(ID_Home_L); + change_page_number = ID_Home_L; + settings.save(); + } + else if (recdat.data[0] == 7) { // Dark mode + dark_mode = true; + BL24CXX::writeOneByte(FONT_EEPROM, dark_mode); + gotoPage(ID_Home_D); + change_page_number = ID_Home_D; + settings.save(); + } + break; + + case AdjustmentKey: // Adjust the interface + if (recdat.data[0] == 1) { // Enter the adjustment interface + updateFan0(); + sendData(probe.offset.z * 100, AUTO_BED_LEVEL_ZOFFSET_VP); + gotoPage(ID_PrintAdjust5_L, ID_PrintAdjust5_D); + } + else if (recdat.data[0] == 2) { // Return to print interface + if (start_print_flag) { + gotoPage(ID_PrintHeating_L, ID_PrintHeating_D); + } + else if (!sdcard_pause_check) { + gotoPage(ID_PrintResume_L, ID_PrintResume_D); + } + else { + refreshTime(); + start_print_flag = false; + } + } + else if (recdat.data[0] == 4) { + updateTempE0(); + gcode.process_subcommands_now(F("M600")); + } + break; + + case FanSpeedKey: // Set fan speed + fan_speed = recdat.data[0]; + thermalManager.set_fan_speed(0, fan_speed); + updateFan0(); + break; + + case PrintSpeedKey: // Set the print speed + feedrate_percentage = recdat.data[0]; + sendData(feedrate_percentage, PRINT_SPEED_RATE_VP); + break; + + case StopPrintKey: // Stop printing + if ((recdat.data[0] == 1) || (recdat.data[0] == 0xF1)) { + sendData(1, Wait_VP); + gotoPage(ID_Processing_L, ID_Processing_D); + sendData(0, PRINT_TIME_HOUR_VP); + sendData(0, PRINT_TIME_MIN_VP); + sendData(0, PRINT_SURPLUS_TIME_HOUR_VP); + sendData(0, PRINT_SURPLUS_TIME_MIN_VP); + sdCardStop(); + print_state = 0; + update_time_value = 0; + } + else if (recdat.data[0] == 0xF0) { + if (start_print_flag) + gotoPage(ID_PrintHeating_L, ID_PrintHeating_D); + else if (!sdcard_pause_check) + gotoPage(ID_PrintResume_L, ID_PrintResume_D); + else { + refreshTime(); + start_print_flag = false; + } + } + break; + + case PausePrintKey: // Suspend printing + if (recdat.data[0] == 0xF0) break; + + if (recdat.data[0] == 0xF1) { + sendData(1, Wait_VP); + gotoPage(ID_Processing_L, ID_Processing_D); + // Reject to receive cmd + change_page_number = ID_PrintResume_D; + waitway = 1; + card.pauseSDPrint(); + pause_action_flag = true; + pause_flag = true; + update_time_value = 0; + sdcard_pause_check = false; + print_state = 1; + } + break; + + case ResumePrintKey: // Restore printing + if (recdat.data[0] == 1) { // Portal restoration printing + if (TERN0(CHECKFILAMENT, runout.filament_ran_out)) gotoPage(ID_FilamentOut_L, ID_FilamentOut_D); + //sendData(1, Wait_VP); + //gotoPage(ID_Processing_L, ID_Processing_D); + card.startOrResumeFilePrinting(); + update_time_value = 0; + sdcard_pause_check = true; + pause_action_flag = false; + pause_flag = false; + refreshTime(); + print_state = 2; + } + else if (recdat.data[0] == 2) { + #if ENABLED(CHECKFILAMENT) + if (runout.filament_ran_out) { + gotoPage(ID_FilamentOut_L, ID_FilamentOut_D); + } + else { + sendData(1, Wait_VP); + gotoPage(ID_Processing_L, ID_Processing_D); + card.startOrResumeFilePrinting(); + print_job_timer.start(); + + update_time_value = 0; + pause_action_flag = false; + sdcard_pause_check = true; + refreshTime(); + print_state = 2; + } + #endif + } + else if (recdat.data[0] == 3) { // Electricity disconnection is restored to print + if (poweroff_continue) { + #if ENABLED(CHECKFILAMENT) + sendData(runout.filament_ran_out ? 0 : 1, CHANGE_FILAMENT_ICON_VP); + gotoPage(ID_Change_L, ID_Change_D); + #endif + } + else if (poweroff_continue == false) { + if (TERN0(CHECKFILAMENT, runout.filament_ran_out)) { gotoPage(ID_FilamentOut_L, ID_FilamentOut_D); break; } + + char cmd[30]; + sprintf_P(cmd, M23_STR, cardRec.filename[FilenamesCount]); + for (char *c = &cmd[4]; *c; c++) *c = tolower(*c); + queue.enqueue_one_now(cmd); + delay(20); + queue.enqueue_now_P(M24_STR); + + // Clean screen + for (uint8_t j = 0; j < 20; j++) sendData(0, PRINT_FILE_TEXT_VP + j); + + sendData(cardRec.display_filename[cardRec.recordcount], PRINT_FILE_TEXT_VP); + delay(2); + TERN_(BABYSTEPPING, sendData(0, AUTO_BED_LEVEL_ZOFFSET_VP)); + feedrate_percentage = 100; + sendData(feedrate_percentage, PRINT_SPEED_RATE_VP); + zprobe_zoffset = last_zoffset; + sendData(probe.offset.z * 100, AUTO_BED_LEVEL_ZOFFSET_VP); + poweroff_continue = true; + gotoPage(ID_PrintHeating_L, ID_PrintHeating_D); + sdcard_pause_check = true; + } + } + else if (recdat.data[0] == 4) { // Card withdrawing to print + if (!card.flag.mounted) { + update_sd = true; + sdCardUpdate(); + gotoPage(ID_MediaFail_L, ID_MediaFail_D); + } + else { + if (TERN0(CHECKFILAMENT, runout.filament_ran_out)) gotoPage(ID_FilamentOut_L, ID_FilamentOut_D); + sendData(1, Wait_VP); + gotoPage(ID_Processing_L, ID_Processing_D); + card.startOrResumeFilePrinting(); + update_time_value = 0; + sdcard_pause_check = true; + pause_action_flag = false; + print_state = 2; + for (uint16_t i = 0;i < cardRec.Filesum; i++) + if (!strcmp(cardRec.filename[i], &recovery.info.sd_filename[1])) + sendData(cardRec.display_filename[i], PRINT_FILE_TEXT_VP); + + refreshTime(); + } + } + break; + + case CoolScreenKey: // Temperature interface + if (recdat.data[0] == 1) { // PLA Preheat + thermalManager.setTargetHotend(PREHEAT_1_TEMP_HOTEND, 0); + updateTempE0(); + thermalManager.setTargetBed(PREHEAT_1_TEMP_BED); + updateTempBed(); + } + else if (recdat.data[0] == 2) { // ABS Preheat + thermalManager.setTargetHotend(PREHEAT_2_TEMP_HOTEND, 0); + updateTempE0(); + thermalManager.setTargetBed(PREHEAT_2_TEMP_BED); + updateTempBed(); + } + else if (recdat.data[0] == 3) { // Back to Home page + gotoPage(ID_Home_L, ID_Home_D); + } + else if (recdat.data[0] == 0xF1) { // Cool down + #if FAN_COUNT > 0 + FANS_LOOP(i) thermalManager.set_fan_speed(i, 255); + #endif + updateFan0(); + thermalManager.setTargetHotend(0, 0); + updateTempE0(); delay(1); + + #if HAS_HEATED_BED + thermalManager.setTargetBed(0); + updateTempBed(); delay(1); + #endif + + gotoPage(ID_TempChange_L, ID_TempChange_D); + } + else if (recdat.data[0] == 0xF0) { + gotoPage(ID_TempChange_L, ID_TempChange_D); + } + break; + + #if HAS_HOTEND + case Heater0TempEnterKey: + thermalManager.setTargetHotend(recdat.data[0], 0); + updateTempE0(); + break; + #endif + + #if HAS_HEATED_BED + case HotBedTempEnterKey: + thermalManager.setTargetBed(recdat.data[0]); + updateTempBed(); + break; + #endif + + case Heater0LoadEnterKey: + filament_load_0 = float(recdat.data[0]) / 10.0f; + break; + + case AxisPageSelectKey: // Mobile shaft interface + switch (recdat.data[0]) { + case 1: + AxisUnitMode = 1; + axis_unit = 10.0; + gotoPage(ID_Move10_L, ID_Move10_D); + break; + case 2: + AxisUnitMode = 2; + axis_unit = 1.0; + gotoPage(ID_Move1_L, ID_Move1_D); + break; + case 3: + AxisUnitMode = 3; + axis_unit = 0.1; + gotoPage(ID_Move01_L, ID_Move01_D); + break; + case 4: + waitway = 4; + queue.enqueue_now(F("G28")); + update_time_value = 0; + sendData(1, Wait_VP); + gotoPage(ID_AutoHome_L, ID_AutoHome_D); + sendData(0, MOTOR_FREE_ICON_VP); + break; + case 5: // Unlock motor + queue.enqueue_now(F("M84")); + sendData(1, MOTOR_FREE_ICON_VP); + break; + } + break; + + case SettingScreenKey: // Set interface + switch (recdat.data[0]) { + #if HAS_HOTEND + case 2: // Go to Reload Filament + filament_load_0 = 10.0f; + sendData(filament_load_0 * 10.0f, HEAD0_FILAMENT_LOAD_DATA_VP); + updateTempE0(); + delay(2); + gotoPage(ID_Load_L, ID_Load_D); + break; + #endif + + case 3: // Go to Move Axis + AxisUnitMode = 1; + TERN_(HAS_X_AXIS, sendData(current_position.x * 10.0f, AXIS_X_COORD_VP)); + TERN_(HAS_Y_AXIS, sendData(current_position.y * 10.0f, AXIS_Y_COORD_VP)); + TERN_(HAS_Z_AXIS, sendData(current_position.z * 10.0f, AXIS_Z_COORD_VP)); + gotoPage(ID_Move10_L, ID_Move10_D); + break; + + case 4: // Go to Advanced Settings + TERN_(LIN_ADVANCE, sendData(planner.extruder_advance_K[0] * 100, Advance_K_VP)); + gotoPage(ID_AdvWarn_L, ID_AdvWarn_D); + break; + + case 5: // Information + sendPrinterInfo(); + sendData(MARLINVERSION, MARLIN_VERSION_TEXT_VP); + gotoPage(ID_Info_L, ID_Info_D); + break; + + case 7: // Return + gotoPage(ID_Home_L, ID_Home_D); + break; + } + break; + + case SettingBackKey: // Adjust interface Return button + if (recdat.data[0] == 1) { + update_time_value = RTS_UPDATE_VALUE; + //settings.save(); + gotoPage(ID_Home_L, ID_Home_D); + } + else if (recdat.data[0] == 2) { + if (!planner.has_blocks_queued()) { + gotoPage(ID_Level5_L, ID_Level5_D); + } + } + break; + + case BedLevelFunKey: // Leveling interface + if (recdat.data[0] == 1) { // Save the button + settings.save(); + waitway = 6; + queue.enqueue_now(F("G28Z\nG1 F200 Z0.0")); + } + else if (recdat.data[0] == 4) { + queue.enqueue_now(F("G34\nG1 F200 Z0.0")); + } + else if (recdat.data[0] == 5) { + #if ENABLED(FIX_MOUNTED_PROBE) + waitway = 3; + sendData(1, AUTO_BED_LEVEL_ICON_VP); + queue.enqueue_now(F("G29")); + #endif + } + + if (recdat.data[0] == 11) settings.save(); // Adjust interface saving + + sendData(0, MOTOR_FREE_ICON_VP); + break; + + #if HAS_X_AXIS + case XaxismoveKey: { + waitway = 4; + current_position.x = float(recdat.data[0] >= 32768 ? recdat.data[0] - 65536 : recdat.data[0]) / 10.0f; + LIMIT(current_position.x, X_MIN_POS, X_MAX_POS); + RTS_line_to_current(X_AXIS); + sendData(current_position.x * 10.0f, AXIS_X_COORD_VP); + sendData(0, MOTOR_FREE_ICON_VP); + waitway = 0; + } break; + #endif + + #if HAS_Y_AXIS + case YaxismoveKey: { + waitway = 4; + current_position.y = float(recdat.data[0]) / 10.0f; + LIMIT(current_position.y, Y_MIN_POS, Y_MAX_POS); + RTS_line_to_current(Y_AXIS); + sendData(current_position.y * 10.0f, AXIS_Y_COORD_VP); + sendData(0, MOTOR_FREE_ICON_VP); + waitway = 0; + } break; + #endif + + #if HAS_Z_AXIS + case ZaxismoveKey: { + waitway = 4; + current_position.z = float(recdat.data[0]) / 10.0f; + LIMIT(current_position.z, Z_MIN_POS, Z_MAX_POS); + RTS_line_to_current(Z_AXIS); + sendData(current_position.z * 10.0f, AXIS_Z_COORD_VP); + sendData(0, MOTOR_FREE_ICON_VP); + waitway = 0; + } break; + #endif + + case FilamentLoadKey: // Change + switch (recdat.data[0]) { + case 1: + if (planner.has_blocks_queued()) break; + if (TERN0(CHECKFILAMENT, runout.filament_ran_out)) gotoPage(ID_NoFilament_L, ID_NoFilament_D); + current_position.e -= filament_load_0; + + if (thermalManager.degHotend(0) < change_filament_temp_0 - 5) { + sendData(int16_t(change_filament_temp_0), CHANGE_FILAMENT0_TEMP_VP); + gotoPage(ID_LoadCold_L, ID_LoadCold_D); + } + else { + RTS_line_to_current(E_AXIS); + sendData(filament_load_0 * 10.0f, HEAD0_FILAMENT_LOAD_DATA_VP); + } + break; + + case 2: + if (planner.has_blocks_queued()) break; + if (TERN0(CHECKFILAMENT, runout.filament_ran_out)) gotoPage(ID_NoFilament_L, ID_NoFilament_D); + current_position.e += filament_load_0; + + if (thermalManager.degHotend(0) < change_filament_temp_0 - 5) { + sendData(int16_t(change_filament_temp_0), CHANGE_FILAMENT0_TEMP_VP); + gotoPage(ID_LoadCold_L, ID_LoadCold_D); + } + else { + RTS_line_to_current(E_AXIS); + sendData(filament_load_0 * 10.0f, HEAD0_FILAMENT_LOAD_DATA_VP); + } + break; + + case 3: + updateTempE0(); + sendData(filament_load_0 * 10.0f, HEAD0_FILAMENT_LOAD_DATA_VP); + gotoPage(ID_LoadCancel_L, ID_LoadCancel_D); + break; + + case 4: + if (planner.has_blocks_queued()) break; + thermalManager.setTargetHotend(0, 0); + updateTempE0(); + gotoPage(ID_Load_L, ID_Load_D); + filament_load_0 = 10.0f; + sendData(filament_load_0 * 10.0f, HEAD0_FILAMENT_LOAD_DATA_VP); + break; + + case 5: + if (planner.has_blocks_queued()) break; + thermalManager.setTargetHotend(change_filament_temp_0, 0); + updateTempE0(); + gotoPage(ID_LoadHeating_L, ID_LoadHeating_D); + heatway = 1; + break; + + case 6: + if (planner.has_blocks_queued()) break; + filament_load_0 = 10.0f; + sendData(filament_load_0 * 10.0f, HEAD0_FILAMENT_LOAD_DATA_VP); + gotoPage(ID_Load_L, ID_Load_D); + break; + + case 8: + if (planner.has_blocks_queued()) break; + thermalManager.setTargetHotend(change_filament_temp_0, 0); + updateTempE0(); + gotoPage(ID_LoadHeating_L, ID_LoadHeating_D); + heatway = 1; + break; + } + break; + + case FilamentCheckKey: + switch (recdat.data[0]) { + case 1: + TERN_(CHECKFILAMENT, gotoPage(runout.filament_ran_out ? ID_NoFilament_L : ID_Load_L, runout.filament_ran_out ? ID_NoFilament_D : ID_Load_D)); // TODO: add page enum + break; + case 2: + gotoPage(ID_Settings_L, ID_Settings_D); + filament_load_0 = 10.0f; + break; + } + break; + + case PowerContinuePrintKey: // Power off + switch (recdat.data[0]) { + case 1: + if (!poweroff_continue) break; + power_off_type_yes = true; + update_time_value = 0; + gotoPage(ID_PrintHeating_L, ID_PrintHeating_D); + queue.enqueue_now(F("M1000")); + + poweroff_continue = true; + sdcard_pause_check = true; + zprobe_zoffset = probe.offset.z; + sendData(probe.offset.z * 100, AUTO_BED_LEVEL_ZOFFSET_VP); + sendData(feedrate_percentage, PRINT_SPEED_RATE_VP); + print_state = 2; + break; + + case 2: + update_time_value = RTS_UPDATE_VALUE; + gotoPage(ID_Home_L, ID_Home_D); + poweroff_continue = false; + sdcard_pause_check = true; + queue.clear(); + quickstop_stepper(); + print_job_timer.abort(); + thermalManager.disable_all_heaters(); + print_job_timer.reset(); + + #if ALL(SDSUPPORT, POWER_LOSS_RECOVERY) + if (card.flag.mounted) { + card.removeJobRecoveryFile(); + recovery.info.valid_head = 0; + recovery.info.valid_foot = 0; + recovery.close(); + } + #endif + + wait_for_heatup = wait_for_user = false; + print_state = 0; + break; + } + break; + + case SelectFileKey: + if (!sdDetected()) break; + if (recdat.data[0] > cardRec.Filesum) break; + + cardRec.recordcount = recdat.data[0] - 1; + for (uint8_t j = 0; j < 10; j++) { + sendData(0, SELECT_FILE_TEXT_VP + j); + sendData(0, PRINT_FILE_TEXT_VP + j); + } + sendData(cardRec.display_filename[cardRec.recordcount], SELECT_FILE_TEXT_VP); + sendData(cardRec.display_filename[cardRec.recordcount], PRINT_FILE_TEXT_VP); + delay(2); + + for (uint16_t j = 1; j <= cardRec.Filesum; j++) + sendData(uint32_t(0x738E), FilenameNature + j * 16); + + sendData(uint32_t(0x041F), FilenameNature + recdat.data[0] * 16); + sendData(1, FILE1_SELECT_ICON_VP + (recdat.data[0] - 1)); + break; + + case PrintFileKey: // List of print files + switch (recdat.data[0]) { + case 1: { + if (!sdDetected()) break; + if (cardRec.recordcount < 0) break; + char cmd[30]; + char *c; + sprintf_P(cmd, M23_STR, cardRec.filename[cardRec.recordcount]); + for (c = &cmd[4]; *c; c++) *c = tolower(*c); + + ZERO(cmdbuf); + strncpy(cmdbuf, cmd, 20); + FilenamesCount = cardRec.recordcount; + + #if ENABLED(CHECKFILAMENT) + if (runout.filament_ran_out) { + gotoPage(ID_FilamentOut_L, ID_FilamentOut_D); + sdcard_pause_check = false; + break; + } + #endif + + queue.enqueue_one_now(cmd); delay(20); + queue.enqueue_now_P(M24_STR); + + // Clean screen + for (uint8_t j = 0; j < 20; j++) sendData(0, PRINT_FILE_TEXT_VP + j); + + sendData(cardRec.display_filename[cardRec.recordcount], PRINT_FILE_TEXT_VP); + delay(2); + + TERN_(BABYSTEPPING, sendData(0, AUTO_BED_LEVEL_ZOFFSET_VP)); + + feedrate_percentage = 100; + sendData(feedrate_percentage, PRINT_SPEED_RATE_VP); + #if HAS_BED_PROBE + zprobe_zoffset = last_zoffset; + sendData(probe.offset.z * 100, AUTO_BED_LEVEL_ZOFFSET_VP); + #endif + + poweroff_continue = true; + gotoPage(ID_PrintHeating_L, ID_PrintHeating_D); + change_page_number = ID_PrintStatus_D; + update_time_value = 0; + start_print_flag = true; + print_state = 2; + } break; + + case 2: gotoPage(ID_Page2_L, ID_Page2_D); break; + case 3: gotoPage(ID_Page1_L, ID_Page1_D); break; + case 4: gotoPage(ID_Page3_L, ID_Page3_D); break; + case 5: gotoPage(ID_Page2_L, ID_Page2_D); break; + case 6: gotoPage(ID_Page4_L, ID_Page4_D); break; + case 7: gotoPage(ID_Page3_L, ID_Page3_D); break; + case 8: gotoPage(ID_Home_L, ID_Home_D); break; + } + break; + + case StoreMemoryKey: // Initialization + if (recdat.data[0] == 0xF1) { + settings.init_eeprom(); + #if ENABLED(AUTO_BED_LEVELING_BILINEAR) + bool zig = true; + int8_t inStart, inStop, inInc, showcount; + showcount = 0; + for (int8_t y = 0; y < GRID_MAX_POINTS_Y; y++) { + // Away from origin + if (zig) { + inStart = 0; + inStop = GRID_MAX_POINTS_X; + inInc = 1; + } + else { + // Towards origin + inStart = GRID_MAX_POINTS_X - 1; + inStop = -1; + inInc = -1; + } + zig ^= true; + for (int8_t x = inStart; x != inStop; x += inInc) { + sendData(bedlevel.z_values[x][y] * 100, AUTO_BED_LEVEL_1POINT_VP + showcount * 2); + showcount++; + } + } + #endif + sendData(Beep, SoundAddr); + zprobe_zoffset = 0; + last_zoffset = 0; + sendData(probe.offset.z * 100, AUTO_BED_LEVEL_ZOFFSET_VP); + gotoPage(ID_Home_L, ID_Home_D); + } + else if (recdat.data[0] == 0xF0) { + gotoPage(ID_Settings_L, ID_Settings_D); + } + break; + + case AdvancedKey: // Advanced setting interface + switch (recdat.data[0]) { + case 1: { // PID + #if ENABLED(PIDTEMP) + const float hot_p = thermalManager.temp_hotend[0].pid.p() * 100.0f, + hot_i = (thermalManager.temp_hotend[0].pid.i() / 8.0f * 10000.0f) + 0.00001f, + hot_d = thermalManager.temp_hotend[0].pid.d() * 8.0f; + sendData(hot_p, Nozzle_P_VP); + sendData(hot_i, Nozzle_I_VP); + sendData(hot_d, Nozzle_D_VP); + #endif + + #if ENABLED(PIDTEMPBED) + const float bed_p = thermalManager.temp_bed.pid.p() * 100.0f, + bed_i = (thermalManager.temp_bed.pid.i() / 8.0f * 10000.0f) + 0.0001f, + bed_d = thermalManager.temp_bed.pid.d() * 0.8f; + + sendData(bed_p, Hot_Bed_P_VP); + sendData(bed_i, Hot_Bed_I_VP); + sendData(bed_d, Hot_Bed_D_VP); + #endif + gotoPage(ID_TempPID_L, ID_TempPID_D); + } break; + + case 2: // Speed + TERN_(HAS_X_AXIS, sendData(planner.settings.max_feedrate_mm_s[X_AXIS], Vmax_X_VP)); + TERN_(HAS_Y_AXIS, sendData(planner.settings.max_feedrate_mm_s[Y_AXIS], Vmax_Y_VP)); + TERN_(HAS_Z_AXIS, sendData(planner.settings.max_feedrate_mm_s[Z_AXIS], Vmax_Z_VP)); + TERN_(HAS_HOTEND, sendData(planner.settings.max_feedrate_mm_s[E_AXIS], Vmax_E_VP)); + gotoPage(ID_Velocity_L, ID_Velocity_D); + break; + + case 3: // Acceleration + sendData(planner.settings.acceleration, Accel_VP); + sendData(planner.settings.travel_acceleration, A_Travel_VP); + + TERN_(HAS_X_AXIS, sendData(planner.settings.max_acceleration_mm_per_s2[X_AXIS], Amax_X_VP)); + TERN_(HAS_Y_AXIS, sendData(planner.settings.max_acceleration_mm_per_s2[Y_AXIS], Amax_Y_VP)); + TERN_(HAS_Z_AXIS, sendData(planner.settings.max_acceleration_mm_per_s2[Z_AXIS], Amax_Z_VP)); + #if HAS_HOTEND + sendData(planner.settings.retract_acceleration, A_Retract_VP); + sendData(planner.settings.max_acceleration_mm_per_s2[E_AXIS], Amax_E_VP); + #endif + gotoPage(ID_Accel_L, ID_Accel_D); + break; + + #if ENABLED(CLASSIC_JERK) + case 4: // Jerk + TERN_(HAS_X_AXIS, sendData(planner.max_jerk.x * 10.0f, Jerk_X_VP)); + TERN_(HAS_Y_AXIS, sendData(planner.max_jerk.y * 10.0f, Jerk_Y_VP)); + TERN_(HAS_Z_AXIS, sendData(planner.max_jerk.z * 10.0f, Jerk_Z_VP)); + TERN_(HAS_HOTEND, sendData(planner.max_jerk.e * 10.0f, Jerk_E_VP)); + gotoPage(ID_Jerk_L, ID_Jerk_D); + break; + #endif + + case 5: // Steps + TERN_(HAS_X_AXIS, sendData(planner.settings.axis_steps_per_mm[X_AXIS] * 10.0f, Steps_X_VP)); + TERN_(HAS_Y_AXIS, sendData(planner.settings.axis_steps_per_mm[Y_AXIS] * 10.0f, Steps_Y_VP)); + TERN_(HAS_Z_AXIS, sendData(planner.settings.axis_steps_per_mm[Z_AXIS] * 10.0f, Steps_Z_VP)); + TERN_(HAS_HOTEND, sendData(planner.settings.axis_steps_per_mm[E_AXIS] * 10.0f, Steps_E_VP)); + gotoPage(ID_Steps_L, ID_Steps_D); + break; + + case 6: gotoPage(ID_Settings_L, ID_Settings_D); break; // Return + + #if ENABLED(LIN_ADVANCE) + case 7: // Confirm + sendData(planner.extruder_advance_K[0] * 100, Advance_K_VP); + gotoPage(ID_Advanced_L, ID_Advanced_D); + break; + #endif + + case 8: gotoPage(ID_SettingsTMC_L, ID_SettingsTMC_D); break; // TMC + + #if ENABLED(EEPROM_SETTINGS) + case 9: settings.save(); break; // Save Settings + #endif + } + break; + + #if ENABLED(PIDTEMP) + case Nozzle_P: SET_HOTEND_PID(Kp, 0, float(recdat.data[0]) / 100.0f); thermalManager.updatePID(); break; + case Nozzle_I: SET_HOTEND_PID(Ki, 0, float(recdat.data[0]) * 8.0f / 10000.0f); thermalManager.updatePID(); break; + case Nozzle_D: SET_HOTEND_PID(Kd, 0, float(recdat.data[0]) / 8.0f); thermalManager.updatePID(); break; + #endif + + #if ENABLED(PIDTEMPBED) + case Hot_Bed_P: thermalManager.temp_bed.pid.Kp = float(recdat.data[0]) / 100.0f; break; + case Hot_Bed_I: thermalManager.temp_bed.pid.Ki = float(recdat.data[0]) * 8.0f / 10000.0f; break; + case Hot_Bed_D: thermalManager.temp_bed.pid.Kd = float(recdat.data[0]) / 0.8f; break; + #endif + + #if HAS_X_AXIS + case Vmax_X: planner.settings.max_feedrate_mm_s[X_AXIS] = recdat.data[0]; break; + case Amax_X: planner.settings.max_acceleration_mm_per_s2[X_AXIS] = recdat.data[0]; break; + case Steps_X: planner.settings.axis_steps_per_mm[X_AXIS] = float(recdat.data[0]) / 10.0f; break; + #if ENABLED(CLASSIC_JERK) + case Jerk_X: planner.max_jerk.x = float(recdat.data[0]) / 10.0f; break; + #endif + #endif + #if HAS_Y_AXIS + case Vmax_Y: planner.settings.max_feedrate_mm_s[Y_AXIS] = recdat.data[0]; break; + case Amax_Y: planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = recdat.data[0]; break; + case Steps_Y: planner.settings.axis_steps_per_mm[Y_AXIS] = float(recdat.data[0]) / 10.0f; break; + #if ENABLED(CLASSIC_JERK) + case Jerk_Y: planner.max_jerk.y = float(recdat.data[0]) / 10.0f; break; + #endif + #endif + #if HAS_Z_AXIS + case Vmax_Z: planner.settings.max_feedrate_mm_s[Z_AXIS] = recdat.data[0]; break; + case Amax_Z: planner.settings.max_acceleration_mm_per_s2[Z_AXIS] = recdat.data[0]; break; + case Steps_Z: planner.settings.axis_steps_per_mm[Z_AXIS] = float(recdat.data[0]) / 10.0f; break; + #if ENABLED(CLASSIC_JERK) + case Jerk_Z: planner.max_jerk.z = float(recdat.data[0]) / 10.0f; break; + #endif + #endif + #if HAS_HOTEND + case Vmax_E: planner.settings.max_feedrate_mm_s[E_AXIS] = recdat.data[0]; break; + case Amax_E: planner.settings.max_acceleration_mm_per_s2[E_AXIS] = recdat.data[0]; break; + case Steps_E: planner.settings.axis_steps_per_mm[E_AXIS] = float(recdat.data[0]) / 10.0f; break; + #if ENABLED(CLASSIC_JERK) + case Jerk_E: planner.max_jerk.e = float(recdat.data[0]) / 10.0f; break; + #endif + case A_Retract: planner.settings.retract_acceleration = recdat.data[0]; break; + #if ENABLED(LIN_ADVANCE) + case Advance_K: planner.extruder_advance_K[0] = float(recdat.data[0]) / 100.0f; break; + #endif + #endif + case Accel: planner.settings.acceleration = recdat.data[0]; break; + case A_Travel: planner.settings.travel_acceleration = recdat.data[0]; break; + + case AdvancedBackKey: gotoPage(ID_Advanced_L, ID_Advanced_D); break; + + #if HAS_FILAMENT_SENSOR + case FilamentChange: // Automatic material + switch (recdat.data[0]) { + case 1: if (runout.filament_ran_out) break; + case 2: + updateTempE0(); + wait_for_heatup = wait_for_user = false; + break; + case 3: pause_menu_response = PAUSE_RESPONSE_EXTRUDE_MORE; break; + case 4: pause_menu_response = PAUSE_RESPONSE_RESUME_PRINT; break; + } + break; + #endif + + #if HAS_BED_PROBE + case ZoffsetUnitKey: // Zoffset unit + switch (recdat.data[0]) { + case 1: gotoPage(ID_PrintAdjust5_L, ID_PrintAdjust5_D); break; + case 2: gotoPage(ID_PrintAdjust1_L, ID_PrintAdjust1_D); break; + case 3: gotoPage(ID_Level5_L, ID_Level5_D); break; + case 4: gotoPage(ID_Level1_L, ID_Level1_D); break; + } + break; + + case ZOffsetKey: + last_zoffset = zprobe_zoffset; + zprobe_zoffset = float(recdat.data[0] >= 32767 ? recdat.data[0] - 65537 : recdat.data[0]) / 100.0f + 0.0001f; + if (WITHIN(zprobe_zoffset, PROBE_OFFSET_ZMIN, PROBE_OFFSET_ZMAX)) + babystep.add_mm(Z_AXIS, zprobe_zoffset - last_zoffset); + probe.offset.z = zprobe_zoffset; + sendData(probe.offset.z * 100, AUTO_BED_LEVEL_ZOFFSET_VP); + break; + #endif + + #if HAS_TRINAMIC_CONFIG + + case TMCDriver: + switch (recdat.data[0]) { + case 1: // Current + #if AXIS_IS_TMC(X) + sendData(stepperX.getMilliamps(), Current_X_VP); + #endif + #if AXIS_IS_TMC(Y) + sendData(stepperY.getMilliamps(), Current_Y_VP); + #endif + #if AXIS_IS_TMC(Z) + sendData(stepperZ.getMilliamps(), Current_Z_VP); + #endif + #if AXIS_IS_TMC(E0) + sendData(stepperE0.getMilliamps(), Current_E_VP); + #endif + gotoPage(ID_DriverA_L, ID_DriverA_D); + break; + + case 2: // Threshold + TERN_(X_HAS_STEALTHCHOP, sendData(stepperX.get_pwm_thrs(), Threshold_X_VP)); + TERN_(Y_HAS_STEALTHCHOP, sendData(stepperY.get_pwm_thrs(), Threshold_Y_VP)); + TERN_(Z_HAS_STEALTHCHOP, sendData(stepperZ.get_pwm_thrs(), Threshold_Z_VP)); + TERN_(E0_HAS_STEALTHCHOP, sendData(stepperE0.get_pwm_thrs(), Threshold_E_VP)); + gotoPage(ID_DriverTrsh_L, ID_DriverTrsh_D); + break; + + #if ENABLED(SENSORLESS_HOMING) + case 3: // Sensorless + TERN_(X_SENSORLESS, sendData(stepperX.homing_threshold(), Sensorless_X_VP)); + TERN_(Y_SENSORLESS, sendData(stepperY.homing_threshold(), Sensorless_Y_VP)); + gotoPage(ID_DriverSens_L, ID_DriverSens_D); + break; + #endif + + case 4: gotoPage(ID_Advanced_L, ID_Advanced_D); break; + case 5: gotoPage(ID_SettingsTMC_L, ID_SettingsTMC_D); break; + } + break; + + #if AXIS_IS_TMC(X) + case Current_X: sprintf_P(cmd, PSTR("M906 X%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + #if X_HAS_STEALTHCHOP + case Threshold_X: sprintf_P(cmd, PSTR("M913 X%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + #if X_SENSORLESS + case Sensorless_X: sprintf_P(cmd, PSTR("M914 X%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + + #if AXIS_IS_TMC(Y) + case Current_Y: sprintf_P(cmd, PSTR("M906 Y%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + #if Y_HAS_STEALTHCHOP + case Threshold_Y: sprintf_P(cmd, PSTR("M913 Y%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + #if Y_SENSORLESS + case Sensorless_Y: sprintf_P(cmd, PSTR("M914 Y%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + + #if AXIS_IS_TMC(Z) + case Current_Z: sprintf_P(cmd, PSTR("M906 Z%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + #if Z_HAS_STEALTHCHOP + case Threshold_Z: sprintf_P(cmd, PSTR("M913 Z%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + + #if AXIS_IS_TMC(E0) + case Current_E: sprintf_P(cmd, PSTR("M906 E%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + #if E0_HAS_STEALTHCHOP + case Threshold_E: sprintf_P(cmd, PSTR("M913 E%i"), recdat.data[0]); queue.inject(cmd); break; + #endif + + #endif // HAS_TRINAMIC_CONFIG + + case ChangePageKey: + switch (change_page_number) { + case ID_Resume_D: case ID_Settings_L: break; // This makes no sense & change_page_number is never set to those values + + case ID_PrintStatus_D: + refreshTime(); + start_print_flag = false; + break; + + case ID_PrintResume_D: gotoPage(ID_PrintResume_L, ID_PrintResume_D); break; + + default: + if (card.isPrinting()) { + for (uint16_t i = 0;i < cardRec.Filesum; i++) + if (!strcmp(cardRec.filename[i], &recovery.info.sd_filename[1])) + sendData(cardRec.display_filename[i], PRINT_FILE_TEXT_VP); + refreshTime(); + } + else + gotoPage(change_page_number); + break; + } + + for (uint8_t i = 0; i < MAX_NUM_FILES; i++) + for (uint8_t j = 0; j < 20; j++) + sendData(0, FILE1_TEXT_VP + i * 20 + j); + + for (uint16_t i = 0; i < cardRec.Filesum; i++) { + for (uint8_t j = 0; j < 20; j++) sendData(0, cardRec.addr[i] + j); + sendData(uint32_t(0x738E), FilenameNature + (i + 1) * 16); + } + + for (uint8_t j = 0; j < 20; j++) { + sendData(0, PRINT_FILE_TEXT_VP + j); // Clean screen + sendData(0, SELECT_FILE_TEXT_VP + j); // Clean filename + } + + // Clean filename Icon + for (uint8_t j = 0; j < 20; j++) + sendData(10, FILE1_SELECT_ICON_VP + j); + + sendData(cardRec.display_filename[cardRec.recordcount], PRINT_FILE_TEXT_VP); + + // Represents to update file list + if (update_sd && lcd_sd_status && IS_SD_INSERTED()) { + for (uint16_t i = 0; i < cardRec.Filesum; i++) { + delay(3); + sendData(cardRec.display_filename[i], cardRec.addr[i]); + sendData(uint32_t(0x738E), FilenameNature + (i + 1) * 16); + sendData(0, FILE1_SELECT_ICON_VP + i); + } + } + + sendPrinterInfo(); + + updateFan0(); + + job_percent = card.percentDone() + 1; + if (job_percent <= 100) sendData(uint8_t(job_percent), PRINT_PROCESS_ICON_VP); + + sendData(uint8_t(card.percentDone()), PRINT_PROCESS_VP); + + TERN_(HAS_BED_PROBE, sendData(probe.offset.z * 100.0f, AUTO_BED_LEVEL_ZOFFSET_VP)); + + sendData(feedrate_percentage, PRINT_SPEED_RATE_VP); + updateTempE0(); + updateTempBed(); + + break; + + default: break; + } + ZERO(&recdat); + recdat.head[0] = FHONE; + recdat.head[1] = FHTWO; +} + +void RTS::sendPrinterInfo() { + sendData(MACVERSION, PRINTER_MACHINE_TEXT_VP); + sendData(SOFTVERSION, PRINTER_VERSION_TEXT_VP); + sendData(CORP_WEBSITE_E, PRINTER_WEBSITE_TEXT_VP); + char printarea[20] = { '\0' }; + sprintf_P(printarea, + PSTR(TERN_(HAS_X_AXIS, "%d x") TERN_(HAS_Y_AXIS, " %d x") TERN_(HAS_Z_AXIS, " %d")) + , X_BED_SIZE, Y_BED_SIZE, Z_MAX_POS + ); + sendData(printarea, PRINTER_PRINTSIZE_TEXT_VP); +} + +void RTS::updateTempE0() { + #if HAS_HOTEND + sendData(thermalManager.degHotend(0), HEAD0_CURRENT_TEMP_VP); + sendData(thermalManager.degTargetHotend(0), HEAD0_SET_TEMP_VP); + #endif +} + +void RTS::updateTempBed() { + #if HAS_HEATED_BED + sendData(thermalManager.degBed(), BED_CURRENT_TEMP_VP); + sendData(thermalManager.degTargetBed(), BED_SET_TEMP_VP); + #endif +} + +void RTS::updateFan0() { + TERN_(HAS_FAN, sendData(thermalManager.fan_speed[0], FAN_SPEED_VP)); +} + +void RTS::onIdle() { + const millis_t ms = millis(); + if (PENDING(ms, next_rts_update_ms)) return; + + // Print the file before the power is off. + if (!power_off_type_yes) { + if (!poweroff_continue || (lcd_sd_status && poweroff_continue)) { + sendData(ExchangePageBase, ExchangepageAddr); + if (startprogress < 0) startprogress = 0; + if (startprogress < 56) sendData(startprogress, START1_PROCESS_ICON_VP); + delay(80); + if (++startprogress > 56) { + sendData(StartSoundSet, SoundAddr); + power_off_type_yes = true; + } + } + + if (lcd_sd_status && poweroff_continue && power_off_type_yes) { + for (uint16_t i = 0; i < cardRec.Filesum; i++) { + if (!strcmp(cardRec.filename[i], &recovery.info.sd_filename[1])) { + sendData(cardRec.display_filename[i], PRINT_FILE_TEXT_VP); + gotoPage(ID_Resume_L, ID_Resume_D); + break; + } + } + } + + if (!poweroff_continue && power_off_type_yes) { + update_time_value = RTS_UPDATE_VALUE; + change_page_number = dark_mode ? ID_Home_D : ID_Home_L; + gotoPage(change_page_number); + } + return; + } + + next_rts_update_ms = ms + RTS_UPDATE_INTERVAL + update_time_value; + + // TODO: optimize the following + if (print_job_timer.duration() != 0) { + duration_t elapsed = print_job_timer.duration(); + static uint8_t last_cardpercentValue = 100; + sendData(elapsed.value / 3600, PRINT_TIME_HOUR_VP); + sendData((elapsed.value % 3600) / 60, PRINT_TIME_MIN_VP); + + if (card.isPrinting() && (last_cardpercentValue != card.percentDone())) { + if (card.percentDone() > 0) { + job_percent = card.percentDone(); + if (job_percent <= 100) sendData(uint8_t(job_percent), PRINT_PROCESS_ICON_VP); + // Estimate remaining time every 20 seconds + static millis_t next_remain_time_update = 0; + if (ELAPSED(ms, next_remain_time_update)) { + if (thermalManager.degHotend(0) >= thermalManager.degTargetHotend(0) - 5) { + remain_time = elapsed.value / (job_percent * 0.01f) - elapsed.value; + next_remain_time_update += 20 * 1000UL; + sendData(remain_time / 3600, PRINT_SURPLUS_TIME_HOUR_VP); + sendData((remain_time % 3600) / 60, PRINT_SURPLUS_TIME_MIN_VP); + } + } + } + else { + sendData(0, PRINT_PROCESS_ICON_VP); + sendData(0, PRINT_SURPLUS_TIME_HOUR_VP); + sendData(0, PRINT_SURPLUS_TIME_MIN_VP); + } + sendData(uint8_t(card.percentDone()), PRINT_PROCESS_VP); + last_cardpercentValue = card.percentDone(); + } + } + + if (pause_action_flag && !sdcard_pause_check && printingIsPaused() && !planner.has_blocks_queued()) { + pause_action_flag = false; + queue.enqueue_now(F("G0 F3000 X0 Y0\nM18 S0")); + } + + TERN_(HAS_Z_AXIS, sendData(current_position.z * 10.0f, AXIS_Z_COORD_VP)); + + #if HAS_HOTEND + if (last_target_temperature[0] != thermalManager.degTargetHotend(0)) + last_target_temperature[0] = thermalManager.degTargetHotend(0); + updateTempE0(); + #endif + + #if HAS_HEATED_BED + if (last_target_temperature_bed != thermalManager.degTargetBed()) + last_target_temperature_bed = thermalManager.degTargetBed(); + updateTempBed(); + #endif + + #if HAS_HOTEND + if (heatway == 1 && !thermalManager.isHeatingHotend(0)) { + heatway = 0; + gotoPage(ID_Load_L, ID_Load_D); + sendData(filament_load_0 * 10.0f, HEAD0_FILAMENT_LOAD_DATA_VP); + } + #endif + + #if HAS_FILAMENT_SENSOR + TERN_(CHECKFILAMENT, sendData(!runout.filament_ran_out, CHANGE_FILAMENT_ICON_VP)); + #endif +} + +// Looping at the loop function +void RTS_Update() { + // Check the status of card + rts.sdCardUpdate(); + + sd_printing = IS_SD_PRINTING(); + card_insert_st = IS_SD_INSERTED(); + + if (!card_insert_st && sd_printing) { + rts.gotoPage(ID_MediaFail_L, ID_MediaFail_D); + rts.sendData(0, CHANGE_SDCARD_ICON_VP); + // Passenger printing so that the nozzle can return to zero + card.pauseSDPrint(); + print_job_timer.pause(); + pause_action_flag = true; + sdcard_pause_check = false; + } + // Update the card withdrawal and card tips icon + if (last_card_insert_st != card_insert_st) { + // The current page is displayed as a card removal page, but the card has been inserted, and the card icon is updated. + rts.sendData(int16_t(card_insert_st), CHANGE_SDCARD_ICON_VP); + last_card_insert_st = card_insert_st; + } + + #if ENABLED(CHECKFILAMENT) + // Check filament status during printing + // The runout class handles the runout threshold + if (card.isPrinting() && poweroff_continue && runout.filament_ran_out) { + rts.sendData(Beep, SoundAddr); + if (TERN0(HAS_HOTEND, thermalManager.still_heating(0)) || TERN0(HAS_HEATED_BED, !thermalManager.isCoolingBed())) { + rts.gotoPage(ID_FilamentOut_L, ID_FilamentOut_D); + } + else { + rts.sendData(1, Wait_VP); + rts.gotoPage(ID_Processing_L, ID_Processing_D); + waitway = 5; + TERN_(POWER_LOSS_RECOVERY, if (recovery.enabled) recovery.save(true, false)); + } + card.pauseSDPrint(); + print_job_timer.pause(); + pause_action_flag = true; + update_time_value = 0; + sdcard_pause_check = false; + rts.print_state = 1; + } + #endif // CHECKFILAMENT + + rts.onIdle(); + + // Wait to receive massage and response + while (rts.receiveData() > 0) rts.handleData(); +} + +void RTS_PauseMoveAxisPage() { + if (waitway == 1) { + rts.gotoPage(ID_PrintResume_L, ID_PrintResume_D); + waitway = 0; + } + else if (waitway == 5) { + rts.gotoPage(ID_FilamentOut_L, ID_FilamentOut_D); + waitway = 0; + } +} + +void RTS_AutoBedLevelPage() { + if (waitway == 3) { + rts.gotoPage(ID_Level5_L, ID_Level5_D); + waitway = 0; + } +} + +void RTS_MoveAxisHoming() { + if (waitway == 4) { + rts.gotoPage((SovolPage)(ID_Move10_L + AxisUnitMode - 1), (SovolPage)(ID_Move10_D + AxisUnitMode - 1)); + waitway = 0; + } + else if (waitway == 6) { + rts.gotoPage(ID_Level5_L, ID_Level5_D); + waitway = 0; + } + else if (waitway == 7) { + // Click Print finish + rts.gotoPage(ID_Home_L, ID_Home_D); + waitway = 0; + } + + TERN_(HAS_X_AXIS, rts.sendData(current_position.x * 10.0f, AXIS_X_COORD_VP)); + TERN_(HAS_Y_AXIS, rts.sendData(current_position.y * 10.0f, AXIS_Y_COORD_VP)); + TERN_(HAS_Z_AXIS, rts.sendData(current_position.z * 10.0f, AXIS_Z_COORD_VP)); +} + +#endif // SOVOL_SV06_RTS diff --git a/Marlin/src/lcd/sovol_rts/sovol_rts.h b/Marlin/src/lcd/sovol_rts/sovol_rts.h new file mode 100644 index 0000000000..8bebdf9a62 --- /dev/null +++ b/Marlin/src/lcd/sovol_rts/sovol_rts.h @@ -0,0 +1,390 @@ +/** + * Marlin 3D Printer Firmware + * Copyright (c) 2023 MarlinFirmware [https://github.com/MarlinFirmware/Marlin] + * + * Based on Sprinter and grbl. + * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +#pragma once + +#include + +/*********************************/ +#define FHONE (0x5A) +#define FHTWO (0xA5) +#define FHLENG (0x06) + +#define MAX_NUM_FILES 20 +#define FILENAME_LEN 20 +#define RTS_UPDATE_INTERVAL 2000 +#define RTS_UPDATE_VALUE (2 * RTS_UPDATE_INTERVAL) + +#define DATA_BUF_SIZE 26 + +/*************Register and Variable addr*****************/ +#define RegAddr_W 0x80 +#define RegAddr_R 0x81 +#define VarAddr_W 0x82 +#define VarAddr_R 0x83 +#define ExchangePageBase 0x5A010000UL // the first page ID. other page = first page ID + relevant num; +#define StartSoundSet 0x060480A0UL // 06,start-music; 04, 4 musics; 80, the volume value; 04, return value about music number. +#define Beep 0x02AF0100UL +#define Beep1 0xFFFF0101UL +#define FONT_EEPROM 90 + +/*variable addr*/ +#define ExchangepageAddr 0x0084 +#define SoundAddr 0x00A0 + +#define START1_PROCESS_ICON_VP 0x1000 +#define PRINT_SPEED_RATE_VP 0x1006 +#define PRINT_PROCESS_ICON_VP 0x100E +#define PRINT_TIME_HOUR_VP 0x1010 +#define PRINT_TIME_MIN_VP 0x1012 +#define PRINT_PROCESS_VP 0x1016 +#define HEAD0_FAN_ICON_VP 0x101E +#define CHANGE_FILAMENT0_TEMP_VP 0x1020 +#define AUTO_BED_LEVEL_ZOFFSET_VP 0x1026 + +#define HEAD0_SET_TEMP_VP 0x1034 +#define HEAD0_CURRENT_TEMP_VP 0x1036 +#define BED_SET_TEMP_VP 0x103A +#define BED_CURRENT_TEMP_VP 0x103C +#define AUTO_HOME_DISPLAY_ICON_VP 0x1042 +#define AXIS_X_COORD_VP 0x1048 +#define AXIS_Y_COORD_VP 0x104A +#define AXIS_Z_COORD_VP 0x104C +#define HEAD0_FILAMENT_LOAD_DATA_VP 0x1054 +#define PRINTER_MACHINE_TEXT_VP 0x1060 +#define PRINTER_VERSION_TEXT_VP 0x106A +#define PRINTER_PRINTSIZE_TEXT_VP 0x1074 +#define PRINTER_WEBSITE_TEXT_VP 0x107E +#define MARLIN_VERSION_TEXT_VP 0x1088 +#define AUTO_BED_LEVEL_ICON_VP 0x108D +#define CHANGE_FILAMENT_ICON_VP 0x108E +#define TWO_EXTRUDER_HOTEND_XOFFSET_VP 0x1092 +#define TWO_EXTRUDER_HOTEND_YOFFSET_VP 0x1094 +#define TWO_EXTRUDER_HOTEND_ZOFFSET_VP 0x1096 +#define AUTO_BED_LEVEL_1POINT_VP 0x1100 + +#define PRINT_SURPLUS_TIME_HOUR_VP 0x1162 +#define PRINT_SURPLUS_TIME_MIN_VP 0x1164 +#define SELECT_MODE_ICON_VP 0x1166 +#define CHANGE_SDCARD_ICON_VP 0x1168 + +#define MOTOR_FREE_ICON_VP 0x1200 +#define FILE1_SELECT_ICON_VP 0x1221 +#define FILE2_SELECT_ICON_VP 0x1222 +#define FILE3_SELECT_ICON_VP 0x1223 +#define FILE4_SELECT_ICON_VP 0x1224 +#define FILE5_SELECT_ICON_VP 0x1225 +#define FILE6_SELECT_ICON_VP 0x1226 +#define FILE7_SELECT_ICON_VP 0x1227 +#define FILE8_SELECT_ICON_VP 0x1228 +#define FILE9_SELECT_ICON_VP 0x1229 +#define FILE10_SELECT_ICON_VP 0x122A +#define FILE11_SELECT_ICON_VP 0x122B +#define FILE12_SELECT_ICON_VP 0x122C +#define FILE13_SELECT_ICON_VP 0x122D +#define FILE14_SELECT_ICON_VP 0x122E +#define FILE15_SELECT_ICON_VP 0x122F +#define FILE16_SELECT_ICON_VP 0x1230 +#define FILE17_SELECT_ICON_VP 0x1231 +#define FILE18_SELECT_ICON_VP 0x1232 +#define FILE19_SELECT_ICON_VP 0x1233 +#define FILE20_SELECT_ICON_VP 0x1234 + +#define FILE1_TEXT_VP 0x200A +#define FILE2_TEXT_VP 0x201E +#define FILE3_TEXT_VP 0x2032 +#define FILE4_TEXT_VP 0x2046 +#define FILE5_TEXT_VP 0x205A +#define FILE6_TEXT_VP 0x206E +#define FILE7_TEXT_VP 0x2082 +#define FILE8_TEXT_VP 0x2096 +#define FILE9_TEXT_VP 0x20AA +#define FILE10_TEXT_VP 0x20BE +#define FILE11_TEXT_VP 0x20D2 +#define FILE12_TEXT_VP 0x20E6 +#define FILE13_TEXT_VP 0x20FA +#define FILE14_TEXT_VP 0x210E +#define FILE15_TEXT_VP 0x2122 +#define FILE16_TEXT_VP 0x2136 +#define FILE17_TEXT_VP 0x214A +#define FILE18_TEXT_VP 0x215E +#define FILE19_TEXT_VP 0x2172 +#define FILE20_TEXT_VP 0x2186 + +#define SELECT_FILE_TEXT_VP 0x219A +#define TWO_COLOR_MODE_ICON_VP 0x21B8 +#define COPY_MODE_ICON_VP 0x21B9 +#define MIRROR_MODE_ICON_VP 0x21BA +#define SINGLE_MODE_ICON_VP 0x21BB +#define EXCHANGE_NOZZLE_ICON_VP 0x21BC +#define PRINT_MODE_ICON_VP 0x21BD +#define PRINT_FILE_TEXT_VP 0x21C0 + +#define Nozzle_P_VP 0x2200 +#define Nozzle_I_VP 0x2204 +#define Nozzle_D_VP 0x2208 +#define Hot_Bed_P_VP 0x220C +#define Hot_Bed_I_VP 0x2240 +#define Hot_Bed_D_VP 0x2244 + +#define Vmax_X_VP 0x2210 +#define Vmax_Y_VP 0x2212 +#define Vmax_Z_VP 0x2214 +#define Vmax_E_VP 0x2216 + +#define Accel_VP 0x2220 +#define A_Retract_VP 0x2222 +#define A_Travel_VP 0x2224 +#define Amax_X_VP 0x2226 +#define Amax_Y_VP 0x2228 +#define Amax_Z_VP 0x222A +#define Amax_E_VP 0x222C + +#define Jerk_X_VP 0x2230 +#define Jerk_Y_VP 0x2232 +#define Jerk_Z_VP 0x2234 +#define Jerk_E_VP 0x2236 + +#define Steps_X_VP 0x1130 +#define Steps_Y_VP 0x1132 +#define Steps_Z_VP 0x1134 +#define Steps_E_VP 0x1136 + +#define Advance_K_VP 0x1138 +#define Time_VP 0x2450 +#define Time1_VP 0x2455 +#define FAN_SPEED_VP 0x2460 +#define Wait_VP 0x2480 +#define Zoffset_UNIT_VP 0x2500 +#define Current_X_VP 0x2468 +#define Current_Y_VP 0x246A +#define Current_Z_VP 0x246C +#define Current_E_VP 0x246F +#define Threshold_X_VP 0x2471 +#define Threshold_Y_VP 0x2473 +#define Threshold_Z_VP 0x2475 +#define Threshold_E_VP 0x2477 +#define Sensorless_X_VP 0x2479 +#define Sensorless_Y_VP 0x247B + +#define FilenameNature 0x6003 + +enum SovolPage : uint8_t { + ID_Startup = 0, // Startup screen + ID_Home_D = 1, ID_Home_L = 55 + ID_Home_D, // Home screen + ID_Page1_D = 2, ID_Page1_L = 55 + ID_Page1_D, // File picker page 1 + ID_Page2_D = 3, ID_Page2_L = 55 + ID_Page2_D, // File picker page 2 + ID_Page3_D = 4, ID_Page3_L = 55 + ID_Page3_D, // File picker page 3 + ID_Page4_D = 5, ID_Page4_L = 55 + ID_Page4_D, // File picker page 4 + ID_ChangeWait_D = 6, ID_ChangeWait_L = 55 + ID_ChangeWait_D, // Wait for filament change to start + ID_Cold_D = 7, ID_Cold_L = 55 + ID_Cold_D, // Nozzle heating, please wait + ID_Change_D = 8, ID_Change_L = 55 + ID_Change_D, // Manually change filament dialog + ID_Finish_D = 9, ID_Finish_L = 55 + ID_Finish_D, // Confirm print finish + ID_PrintHeating_D = 10, ID_PrintHeating_L = 55 + ID_PrintHeating_D, // Wait for heating before print starts + ID_PrintStatus_D = 11, ID_PrintStatus_L = 55 + ID_PrintStatus_D, // Printing status progress + ID_PrintResume_D = 12, ID_PrintResume_L = 55 + ID_PrintResume_D, // Resume printing + ID_PrintAdjust1_D = 14, ID_PrintAdjust1_L = 55 + ID_PrintAdjust1_D, // Modify print settings while printing, 0.01mm z offset + ID_TempChange_D = 15, ID_TempChange_L = 55 + ID_TempChange_D, // Temp / fan change and preset menu + ID_Unload_D = 16, ID_Unload_L = 55 + ID_Unload_D, // Wait for filament unload + ID_Insert_D = 17, ID_Insert_L = 55 + ID_Insert_D, // Insert filament + ID_Advanced_D = 18, ID_Advanced_L = 55 + ID_Advanced_D, // Advanced settings + ID_NoFilament_D = 20, ID_NoFilament_L = 55 + ID_NoFilament_D, // No filament + ID_Settings_D = 21, ID_Settings_L = 55 + ID_Settings_D, // Settings screen + ID_Level1_D = 22, ID_Level1_L = 55 + ID_Level1_D, // Leveling screen 0.01mm + ID_Load_D = 23, ID_Load_L = 55 + ID_Load_D, // Filament loading screen, feed / retreat filament + ID_LoadCold_D = 24, ID_LoadCold_L = 55 + ID_LoadCold_D, // Cold nozzle warning on filament load screen + ID_Velocity_D = 25, ID_Velocity_L = 55 + ID_Velocity_D, // Speed limit settings menu + ID_LoadHeating_D = 26, ID_LoadHeating_L = 55 + ID_LoadHeating_D, // Nozzle heating in filament load screen + ID_LoadCancel_D = 27, ID_LoadCancel_L = 55 + ID_LoadCancel_D, // Filament change menu, cancel feed / retreat + ID_PrintAdjust5_D = 28, ID_PrintAdjust5_L = 55 + ID_PrintAdjust5_D, // Modify print settings while printing, 0.05mm z offset + ID_Move10_D = 29, ID_Move10_L = 55 + ID_Move10_D, // Move axis, 10mm + ID_Move1_D = 30, ID_Move1_L = 55 + ID_Move1_D, // Move axis, 1mm + ID_Move01_D = 31, ID_Move01_L = 55 + ID_Move01_D, // Move axis, 0.1mm + ID_AutoHome_D = 32, ID_AutoHome_L = 55 + ID_AutoHome_D, // Auto homing in progress + ID_Info_D = 33, ID_Info_L = 55 + ID_Info_D, // Printer info screen + ID_Accel_D = 34, ID_Accel_L = 55 + ID_Accel_D, // Accelaration settings menu + ID_Jerk_D = 35, ID_Jerk_L = 55 + ID_Jerk_D, // Jerk settings menu + ID_Resume_D = 36, ID_Resume_L = 55 + ID_Resume_D, // Resume print after power loss + ID_Steps_D = 37, ID_Steps_L = 55 + ID_Steps_D, // Steps settings menu + ID_ABL_Wait_D = 38, ID_ABL_Wait_L = 55 + ID_ABL_Wait_D, // Auto leveling, please wait + ID_FilamentOut_D = 39, ID_FilamentOut_L = 55 + ID_FilamentOut_D, // Click yes to heat and change filament + ID_Processing_D = 40, ID_Processing_L = 55 + ID_Processing_D, // Processing please wait + ID_TempPID_D = 41, ID_TempPID_L = 55 + ID_TempPID_D, // PID settings menu + ID_Purge_D = 43, ID_Purge_L = 55 + ID_Purge_D, // Wait for filament purge + ID_PurgeMore_D = 44, ID_PurgeMore_L = 56 + ID_PurgeMore_D, // Purge more or resume screen + ID_HeatNozzle_D = 45, ID_HeatNozzle_L = 54 + ID_HeatNozzle_D, // Heat nozzle after pause + ID_MediaFail_D = 46, ID_MediaFail_L = 55 + ID_MediaFail_D, // Sd card removed + ID_BrowseNoSd_D = 47, ID_BrowseNoSd_L = 55 + ID_BrowseNoSd_D, // No sd card on browse screen + ID_AdvWarn_D = 49, ID_AdvWarn_L = 55 + ID_AdvWarn_D, // Warning when entering advanced settings + ID_KillRunaway_D = 52, ID_KillRunaway_L = 55 + ID_KillRunaway_D, // Thermal runaway + ID_KillHeat_D = 53, ID_KillHeat_L = 55 + ID_KillHeat_D, // Thermistor error + ID_KillBadTemp_D = 54, ID_KillBadTemp_L = 55 + ID_KillBadTemp_D, // Heating failed + ID_KillHome_D = 55, ID_KillHome_L = 55 + ID_KillHome_D, // Auto-home failed + ID_Level5_D = 111, ID_Level5_L = 6 + ID_Level5_D, // Leveling screen 0.05mm + ID_DriverError_D = 112, ID_DriverError_L = 6 + ID_DriverError_D, // Driver error + ID_SettingsTMC_D = 113, ID_SettingsTMC_L = 6 + ID_SettingsTMC_D, // TMC Driver settings + ID_DriverA_D = 114, ID_DriverA_L = 6 + ID_DriverA_D, // TMC Driver current settings + ID_DriverTrsh_D = 115, ID_DriverTrsh_L = 6 + ID_DriverTrsh_D, // TMC Driver hybrid treshold settings + ID_DriverSens_D = 116, ID_DriverSens_L = 6 + ID_DriverSens_D, // TMC Driver sensorless homing settings + ID_ABL_HeatWait_D = 123, ID_ABL_HeatWait_L = 1 + ID_ABL_HeatWait_D, // Wait for nozzle & bed to heat up +}; + +/************struct**************/ + +typedef struct DataBuf { + uint8_t len; + uint8_t head[2]; + uint8_t command; + uint32_t addr; + uint32_t bytelen; + uint16_t data[32]; + uint8_t reserv[4]; +} DB; + +typedef struct CardRecord { + int16_t recordcount; + int16_t Filesum; + uint32_t addr[MAX_NUM_FILES]; + char display_filename[MAX_NUM_FILES][FILENAME_LEN]; + char filename[MAX_NUM_FILES][FILENAME_LEN]; +} CRec; + +class RTS { + public: + RTS(); + static int16_t receiveData(); + static void sdCardInit(); + static bool sdDetected(); + static void sdCardUpdate(); + static void sendData(); + static void sendData(const String&, const uint32_t, const uint8_t=VarAddr_W); + static void sendData(const char[], const uint32_t, const uint8_t=VarAddr_W); + static void sendData(const char, const uint32_t, const uint8_t=VarAddr_W); + static void sendData(const int16_t, const uint32_t, const uint8_t=VarAddr_W); + static void sendData(const uint32_t, const uint32_t, const uint8_t=VarAddr_W); + + static void sendData(const uint8_t str[], const uint32_t addr, const uint8_t cmd=VarAddr_W) { sendData((char *)str, addr, cmd); } + static void sendData(const uint16_t n, const uint32_t addr, const uint8_t cmd=VarAddr_W) { sendData(int16_t(n), addr, cmd); } + static void sendData(const_float_t n, const uint32_t addr, const uint8_t cmd=VarAddr_W) { sendData(int16_t(n), addr, cmd); } //was originally int16 ? + static void sendData(const int32_t n, const uint32_t addr, const uint8_t cmd=VarAddr_W) { sendData(uint32_t(n), addr, cmd); } + static void sendData(const int n, const uint32_t addr, const uint8_t cmd=VarAddr_W) { sendData(int16_t(n), addr, cmd); } + + static void sdCardStop(); + static void handleData(); + static void init(); + + static uint8_t print_state; + static bool start_print_flag; + + static bool dark_mode; + static void gotoPage(SovolPage page) { sendData(ExchangePageBase + page, ExchangepageAddr); } + static void gotoPage(SovolPage p1, SovolPage p2) { gotoPage(dark_mode ? p2 : p1); } + static void gotoPageBeep(SovolPage p1, SovolPage p2) { gotoPage(p1, p2); sendData(Beep1, SoundAddr); } + + static void sendPrinterInfo(); + static void updateTempE0(); + static void updateTempBed(); + static void updateFan0(); + + static void onIdle(); + + static void refreshTime() { sendData(1, dark_mode ? Time_VP : Time1_VP); gotoPage(ID_PrintStatus_L, ID_PrintStatus_D); } + + static DB recdat; + static DB snddat; + private: + static uint8_t databuf[DATA_BUF_SIZE]; +}; + +extern RTS rts; + +enum PROC_COM { + MainPageKey = 0, + AdjustmentKey, + PrintSpeedKey, + StopPrintKey, + PausePrintKey, + ResumePrintKey, + ZOffsetKey, + TempScreenKey, + CoolScreenKey, + Heater0TempEnterKey, Heater1TempEnterKey, + HotBedTempEnterKey, + SettingScreenKey, + SettingBackKey, + BedLevelFunKey, + AxisPageSelectKey, + XaxismoveKey, YaxismoveKey, ZaxismoveKey, + SelectExtruderKey, + Heater0LoadEnterKey, + FilamentLoadKey, + Heater1LoadEnterKey, + SelectLanguageKey, + FilamentCheckKey, + PowerContinuePrintKey, + PrintSelectModeKey, + XhotendOffsetKey, YhotendOffsetKey, ZhotendOffsetKey, + StoreMemoryKey, + PrintFileKey, + SelectFileKey, + AdvancedKey, + Nozzle_P, Nozzle_I, Nozzle_D, + Hot_Bed_P, Hot_Bed_I, Hot_Bed_D, + Vmax_X, Vmax_Y, Vmax_Z, Vmax_E, + Accel, A_Retract, A_Travel, + Amax_X, Amax_Y, Amax_Z, Amax_E, + Jerk_X, Jerk_Y, Jerk_Z, Jerk_E, + Steps_X, Steps_Y, Steps_Z, Steps_E, + Advance_K, + AdvancedBackKey, + FilamentChange, + FanSpeedKey, + ZoffsetUnitKey, + TMCDriver, + Current_X, Current_Y, Current_Z, Current_E, + Threshold_X, Threshold_Y, Threshold_Z, Threshold_E, + Sensorless_X, Sensorless_Y, + ChangePageKey +}; + +const uint32_t Addrbuf[] = { + 0x1002, 0x1004, 0x1006, 0x1008, 0x100A, 0x100C, 0x1026, 0x1030, 0x1032, 0x1034, + 0x1038, 0x103A, 0x103E, 0x1040, 0x1044, 0x1046, 0x1048, 0x104A, 0x104C, 0x104E, + 0x1054, 0x1056, 0x1058, 0x105C, 0x105E, 0x105F, 0x1090, 0x1092, 0x1094, 0x1096, + 0x1098, 0x2198, 0x2199, 0x21E0, 0x2200, 0x2204, 0x2208, 0x220C, 0x2240, 0x2244, + 0x2210, 0x2212, 0x2214, 0x2216, 0x2220, 0x2222, 0x2224, 0x2226, 0x2228, 0x222A, + 0x222C, 0x2230, 0x2232, 0x2234, 0x2236, 0x1130, 0x1132, 0x1134, 0x1136, 0x1138, + 0x2250, 0x2300, 0x2460, 0x2464, 0x2466, 0x2468, 0x246A, 0x246C, 0x246F, 0x2471, + 0x2473, 0x2475, 0x2477, 0x2479, 0x247B, 0x110E, 0 +}; + +extern void RTS_Update(); +extern void RTS_Init(); + +extern int16_t update_time_value; +extern bool poweroff_continue; +extern bool sdcard_pause_check; +extern bool sd_printing_autopause; +extern bool pause_flag; + +void RTS_AutoBedLevelPage(); +void RTS_MoveAxisHoming(); +void RTS_PauseMoveAxisPage(); diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index cb2a8f283a..999e07ea74 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -30,6 +30,9 @@ #include "../sd/cardreader.h" #include "temperature.h" #include "../lcd/marlinui.h" +#if ENABLED(SOVOL_SV06_RTS) + #include "../lcd/sovol_rts/sovol_rts.h" +#endif #if ENABLED(FT_MOTION) #include "ft_motion.h" @@ -272,8 +275,12 @@ void Endstops::not_homing() { #if ENABLED(VALIDATE_HOMING_ENDSTOPS) // If the last move failed to trigger an endstop, call kill void Endstops::validate_homing_move() { - if (trigger_state()) hit_on_purpose(); - else kill(GET_TEXT_F(MSG_KILL_HOMING_FAILED)); + if (trigger_state()) + hit_on_purpose(); + else { + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillHome_L, ID_KillHome_D)); + kill(GET_TEXT_F(MSG_KILL_HOMING_FAILED)); + } } #endif diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 5c11df2c6a..7e5c4bc9fd 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -52,6 +52,8 @@ #if ENABLED(DWIN_CREALITY_LCD) #include "../lcd/e3v2/creality/dwin.h" +#elif ENABLED(SOVOL_SV06_RTS) + #include "../lcd/sovol_rts/sovol_rts.h" #endif #if ENABLED(EXTENSIBLE_UI) @@ -695,7 +697,11 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(USE_CONTROLLER_FAN, controllerFan.update()); // Run UI update - ui.update(); + #if ENABLED(SOVOL_SV06_RTS) + RTS_Update(); + #else + ui.update(); + #endif return temp_ready; } @@ -886,11 +892,15 @@ volatile bool Temperature::raw_temps_ready = false; temp_change_ms = ms + SEC_TO_MS(watch_temp_period); // - move the expiration timer up if (current_temp > watch_temp_target) heated = true; // - Flag if target temperature reached } - else if (ELAPSED(ms, temp_change_ms)) // Watch timer expired + else if (ELAPSED(ms, temp_change_ms)) { // Watch timer expired + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillHeat_L, ID_KillHeat_D)); _TEMP_ERROR(heater_id, FPSTR(str_t_heating_failed), MSG_ERR_HEATING_FAILED, current_temp); + } } - else if (current_temp < target - (MAX_OVERSHOOT_PID_AUTOTUNE)) // Heated, then temperature fell too far? + else if (current_temp < target - (MAX_OVERSHOOT_PID_AUTOTUNE)) { // Heated, then temperature fell too far? + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillRunaway_L, ID_KillRunaway_D)); _TEMP_ERROR(heater_id, FPSTR(str_t_thermal_runaway), MSG_ERR_THERMAL_RUNAWAY, current_temp); + } } #endif } // every 2 seconds @@ -903,6 +913,7 @@ volatile bool Temperature::raw_temps_ready = false; TERN_(DWIN_CREALITY_LCD, dwinPopupTemperature(0)); TERN_(EXTENSIBLE_UI, ExtUI::onPIDTuning(ExtUI::pidresult_t::PID_TUNING_TIMEOUT)); TERN_(HOST_PROMPT_SUPPORT, hostui.notify(GET_TEXT_F(MSG_PID_TIMEOUT))); + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillHeat_L, ID_KillHeat_D)); SERIAL_ECHOPGM(STR_PID_AUTOTUNE); SERIAL_ECHOLNPGM(STR_PID_TIMEOUT); break; } @@ -1580,6 +1591,7 @@ void Temperature::_temp_error( void Temperature::maxtemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_TEMP, const celsius_float_t deg)) { #if HAS_HOTEND || HAS_HEATED_BED + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillBadTemp_L, ID_KillBadTemp_D)); TERN_(DWIN_CREALITY_LCD, dwinPopupTemperature(1)); TERN_(EXTENSIBLE_UI, ExtUI::onMaxTempError(heater_id)); #endif @@ -1588,6 +1600,7 @@ void Temperature::maxtemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_TEMP, const celsius_float_t deg)) { #if HAS_HOTEND || HAS_HEATED_BED + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillBadTemp_L, ID_KillBadTemp_D)); TERN_(DWIN_CREALITY_LCD, dwinPopupTemperature(0)); TERN_(EXTENSIBLE_UI, ExtUI::onMinTempError(heater_id)); #endif @@ -1793,7 +1806,10 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T #if ENABLED(THERMAL_PROTECTION_HOTENDS) { const auto deg = degHotend(e); - if (deg > temp_range[e].maxtemp) MAXTEMP_ERROR(e, deg); + if (deg > temp_range[e].maxtemp) { + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillBadTemp_L, ID_KillBadTemp_D)); + MAXTEMP_ERROR(e, deg); + } } #endif @@ -1814,6 +1830,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T if (watch_hotend[e].check(temp)) // Increased enough? start_watching_hotend(e); // If temp reached, turn off elapsed check else { + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillHeat_L, ID_KillHeat_D)); TERN_(DWIN_CREALITY_LCD, dwinPopupTemperature(0)); TERN_(EXTENSIBLE_UI, ExtUI::onHeatingError(e)); _TEMP_ERROR(e, FPSTR(str_t_heating_failed), MSG_ERR_HEATING_FAILED, temp); @@ -1833,7 +1850,10 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T #if ENABLED(THERMAL_PROTECTION_BED) { const auto deg = degBed(); - if (deg > BED_MAXTEMP) MAXTEMP_ERROR(H_BED, deg); + if (deg > BED_MAXTEMP) { + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillBadTemp_L, ID_KillBadTemp_D)); + MAXTEMP_ERROR(H_BED, deg); + } } #endif @@ -1845,6 +1865,7 @@ void Temperature::mintemp_error(const heater_id_t heater_id OPTARG(ERR_INCLUDE_T if (watch_bed.check(deg)) // Increased enough? start_watching_bed(); // If temp reached, turn off elapsed check else { + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillHeat_L, ID_KillHeat_D)); TERN_(DWIN_CREALITY_LCD, dwinPopupTemperature(0)); TERN_(EXTENSIBLE_UI, ExtUI::onHeatingError(H_BED)); _TEMP_ERROR(H_BED, FPSTR(str_t_heating_failed), MSG_ERR_HEATING_FAILED, deg); @@ -3298,6 +3319,7 @@ void Temperature::init() { } // fall through case TRRunaway: + TERN_(SOVOL_SV06_RTS, rts.gotoPageBeep(ID_KillRunaway_L, ID_KillRunaway_D)); TERN_(DWIN_CREALITY_LCD, dwinPopupTemperature(0)); TERN_(EXTENSIBLE_UI, ExtUI::onHeatingError(heater_id)); _TEMP_ERROR(heater_id, FPSTR(str_t_thermal_runaway), MSG_ERR_THERMAL_RUNAWAY, current); @@ -4624,6 +4646,10 @@ void Temperature::isr() { hmiFlag.heat_flag = 0; duration_t elapsed = print_job_timer.duration(); // Print timer dwin_heat_time = elapsed.value; + #elif ENABLED(SOVOL_SV06_RTS) + update_time_value = RTS_UPDATE_VALUE; + if (IS_SD_PRINTING()) rts.refreshTime(); + rts.start_print_flag = false; #else ui.reset_status(); #endif diff --git a/Marlin/src/module/temperature.h b/Marlin/src/module/temperature.h index bb38922d7e..d5ed80ad3a 100644 --- a/Marlin/src/module/temperature.h +++ b/Marlin/src/module/temperature.h @@ -1027,14 +1027,14 @@ class Temperature { #endif #endif - static bool still_heating(const uint8_t e) { - return degTargetHotend(e) > TEMP_HYSTERESIS && ABS(wholeDegHotend(e) - degTargetHotend(e)) > TEMP_HYSTERESIS; - } - static bool degHotendNear(const uint8_t e, const celsius_t temp) { return ABS(wholeDegHotend(e) - temp) < (TEMP_HYSTERESIS); } + static bool still_heating(const uint8_t e) { + return degTargetHotend(e) > TEMP_HYSTERESIS && !degHotendNear(e, degTargetHotend(e)); + } + // Start watching a Hotend to make sure it's really heating up static void start_watching_hotend(const uint8_t E_NAME) { UNUSED(HOTEND_INDEX); diff --git a/Marlin/src/sd/cardreader.cpp b/Marlin/src/sd/cardreader.cpp index 56daa369fc..facd2d811a 100644 --- a/Marlin/src/sd/cardreader.cpp +++ b/Marlin/src/sd/cardreader.cpp @@ -38,6 +38,8 @@ #if ENABLED(DWIN_CREALITY_LCD) #include "../lcd/e3v2/creality/dwin.h" +#elif ENABLED(SOVOL_SV06_RTS) + #include "../lcd/sovol_rts/sovol_rts.h" #endif #include "../module/planner.h" // for synchronize @@ -1459,6 +1461,7 @@ void CardReader::fileHasFinished() { if (jobRecoverFileExists()) { recovery.init(); removeFile(recovery.filename); + TERN_(SOVOL_SV06_RTS, poweroff_continue = false); #if ENABLED(DEBUG_POWER_LOSS_RECOVERY) SERIAL_ECHOLN(F("Power-loss file delete"), jobRecoverFileExists() ? F(" failed.") : F("d.")); #endif diff --git a/ini/features.ini b/ini/features.ini index 33d1f31279..420ba8e131 100644 --- a/ini/features.ini +++ b/ini/features.ini @@ -48,6 +48,7 @@ DWIN_CREALITY_LCD = build_src_filter=+ DWIN_CREALITY_LCD_JYERSUI = build_src_filter=+ IS_DWIN_MARLINUI = build_src_filter=+ +SOVOL_SV06_RTS = build_src_filter=+ HAS_GRAPHICAL_TFT = build_src_filter=+ - - HAS_UI_320X.+ = build_src_filter=+ HAS_UI_480X.+ = build_src_filter=+ diff --git a/platformio.ini b/platformio.ini index 76200cbbd5..5c9be792f0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -56,7 +56,7 @@ lib_deps = default_src_filter = + - - ; LCDs and Controllers - - - - - - - - - - + - - - - - - ; Marlin HAL -