diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index 548665543e..3e066bfbf1 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1012,7 +1012,7 @@ * The probe replaces the Z-MIN endstop and is used for Z homing. * (Automatically enables USE_PROBE_FOR_Z_HOMING.) */ -#define Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN +//#define Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN // Force the use of the probe for Z-axis homing //#define USE_PROBE_FOR_Z_HOMING @@ -1364,7 +1364,7 @@ #define X_MIN_POS ((X_BED_SIZE / 2) - BAD_CENTER_X_POS) #define Y_MIN_POS ((Y_BED_SIZE / 2) - BAD_CENTER_Y_POS) #define Z_MIN_POS 0 -#define X_MAX_POS X_BED_SIZE +#define X_MAX_POS 338.5 #define Y_MAX_POS Y_BED_SIZE #define Z_MAX_POS 215 //#define I_MIN_POS 0 @@ -1424,13 +1424,30 @@ * RAMPS-based boards use SERVO3_PIN for the first runout sensor. * For other boards you may need to define FIL_RUNOUT_PIN, FIL_RUNOUT2_PIN, etc. */ -//#define FILAMENT_RUNOUT_SENSOR -#if ENABLED(FILAMENT_RUNOUT_SENSOR) - #define FIL_RUNOUT_ENABLED_DEFAULT true // Enable the sensor on startup. Override with M412 followed by M500. - #define NUM_RUNOUT_SENSORS 1 // Number of sensors, up to one per extruder. Define a FIL_RUNOUT#_PIN for each. - - #define FIL_RUNOUT_STATE LOW // Pin state indicating that filament is NOT present. - #define FIL_RUNOUT_PULLUP // Use internal pullup for filament runout pins. + #define FILAMENT_RUNOUT_SENSOR + + #define CUSTOM_FILAMENT_SENSOR // Snapmaker J1 custom ADC filament runout sensors. + + #if ENABLED(FILAMENT_RUNOUT_SENSOR) + #define FIL_RUNOUT_ENABLED_DEFAULT true // Enable the sensor on startup. Override with M412 followed by M500. + #define NUM_RUNOUT_SENSORS 2 // Number of sensors, up to one per extruder. Define a FIL_RUNOUT#_PIN for each. + + + // Not used when CUSTOM_FILAMENT_SENSOR enabled, but must be defined. + #ifndef FIL_RUNOUT_PIN + #define FIL_RUNOUT_PIN -1 // Dummy pin for custom ADC sensor + #endif + #ifndef FIL_RUNOUT2_PIN + #define FIL_RUNOUT2_PIN -1 // Dummy pin for custom ADC sensor + #endif + #define FIL_RUNOUT_STATE HIGH // Placeholder state (unused with -1 pins) + #define FIL_RUNOUT1_STATE FIL_RUNOUT_STATE + #define FIL_RUNOUT2_STATE FIL_RUNOUT_STATE + #endif + + + //#define FIL_RUNOUT_STATE LOW // Pin state indicating that filament is NOT present. + //#define FIL_RUNOUT_PULLUP // Use internal pullup for filament runout pins. //#define FIL_RUNOUT_PULLDOWN // Use internal pulldown for filament runout pins. //#define WATCH_ALL_RUNOUT_SENSORS // Execute runout script on any triggering sensor, not only for the active extruder. // This is automatically enabled for MIXING_EXTRUDERs. @@ -1484,7 +1501,7 @@ // large enough to avoid false positives.) //#define FILAMENT_MOTION_SENSOR #endif -#endif + //=========================================================================== //=============================== Bed Leveling ============================== @@ -1543,8 +1560,8 @@ */ //#define PREHEAT_BEFORE_LEVELING #if ENABLED(PREHEAT_BEFORE_LEVELING) - #define LEVELING_NOZZLE_TEMP 120 // (°C) Only applies to E0 at this time - #define LEVELING_BED_TEMP 50 + #define LEVELING_NOZZLE_TEMP 200 // (°C) Only applies to E0 at this time + #define LEVELING_BED_TEMP 100 #endif /** @@ -1593,8 +1610,8 @@ #if EITHER(AUTO_BED_LEVELING_LINEAR, AUTO_BED_LEVELING_BILINEAR) // Set the number of grid points per dimension. - #define GRID_MAX_POINTS_X 3 - #define GRID_MAX_POINTS_Y GRID_MAX_POINTS_X + #define GRID_MAX_POINTS_X 5 + #define GRID_MAX_POINTS_Y 3 // Probe along the Y axis, advancing X after each column //#define PROBE_Y_FIRST @@ -1876,16 +1893,15 @@ * P1 Raise the nozzle always to Z-park height. * P2 Raise the nozzle by Z-park amount, limited to Z_MAX_POS. */ -//#define NOZZLE_PARK_FEATURE +#define NOZZLE_PARK_FEATURE #if ENABLED(NOZZLE_PARK_FEATURE) - // Specify a park position as { X, Y, Z_raise } - #define NOZZLE_PARK_POINT { (X_MIN_POS + 10), (Y_MAX_POS - 10), 20 } - //#define NOZZLE_PARK_X_ONLY // X move only is required to park - //#define NOZZLE_PARK_Y_ONLY // Y move only is required to park + // Define park positions as separate { X, Y, Z_raise } for each extruder + #define NOZZLE_PARK_POINT_T0 { -6, Y_MIN_POS, 20 } /* T0: park position */ + #define NOZZLE_PARK_POINT_T1 { 331, Y_MIN_POS, 20 } /* T1: park position */ #define NOZZLE_PARK_Z_RAISE_MIN 2 // (mm) Always raise Z by at least this distance - #define NOZZLE_PARK_XY_FEEDRATE 100 // (mm/s) X and Y axes feedrate (also used for delta Z axis) - #define NOZZLE_PARK_Z_FEEDRATE 5 // (mm/s) Z axis feedrate (not used for delta printers) + #define NOZZLE_PARK_XY_FEEDRATE 100 // (mm/s) X and Y axes feedrate + #define NOZZLE_PARK_Z_FEEDRATE 5 // (mm/s) Z axis feedrate #endif /** @@ -2908,4 +2924,4 @@ * */ #define DEBUG_IO PD0 -#define DEBUG_ISR_CPU_USAGE \ No newline at end of file +#define DEBUG_ISR_CPU_USAGE diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index 28447f135a..81e2f9a0b4 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -286,7 +286,7 @@ * Thermal Protection parameters for the heated chamber. */ #if ENABLED(THERMAL_PROTECTION_CHAMBER) - #define THERMAL_PROTECTION_CHAMBER_PERIOD 20 // Seconds + #define THERMAL_PROTECTION_CHAMBER_PERIOD 60 // Seconds #define THERMAL_PROTECTION_CHAMBER_HYSTERESIS 2 // Degrees Celsius /** @@ -945,7 +945,7 @@ * Set DISABLE_INACTIVE_? 'true' to shut down axis steppers after an idle period. * The Deactive Time can be overridden with M18 and M84. Set to 0 for No Timeout. */ -#define DEFAULT_STEPPER_DEACTIVE_TIME 120 +#define DEFAULT_STEPPER_DEACTIVE_TIME 300 #define DISABLE_INACTIVE_X true #define DISABLE_INACTIVE_Y true #define DISABLE_INACTIVE_Z true // Set 'false' if the nozzle could fall onto your printed part! @@ -1822,7 +1822,7 @@ * * Warning: Does not respect endstops! */ -//#define BABYSTEPPING +#define BABYSTEPPING #if ENABLED(BABYSTEPPING) //#define INTEGRATED_BABYSTEPPING // EXPERIMENTAL integration of babystepping into the Stepper ISR //#define BABYSTEP_WITHOUT_HOMING @@ -1872,9 +1872,9 @@ #define LIN_ADVANCE #if ENABLED(LIN_ADVANCE) //#define EXTRA_LIN_ADVANCE_K // Enable for second linear advance constants - #define LIN_ADVANCE_K 0.02 // Unit: mm compression per 1mm/s extruder speed + #define LIN_ADVANCE_K 0.04 // Unit: mm compression per 1mm/s extruder speed //#define LA_DEBUG // If enabled, this will generate debug information output over USB. - #define EXPERIMENTAL_SCURVE // Enable this option to permit S-Curve Acceleration + //#define EXPERIMENTAL_SCURVE // Enable this option to permit S-Curve Acceleration #endif // @section leveling @@ -2135,13 +2135,13 @@ // For debug-echo: 128 bytes for the optimal speed. // Other output doesn't need to be that speedy. // :[0, 2, 4, 8, 16, 32, 64, 128, 256] -#define TX_BUFFER_SIZE 0 +#define TX_BUFFER_SIZE 4 // Host Receive Buffer Size // Without XON/XOFF flow control (see SERIAL_XON_XOFF below) 32 bytes should be enough. // To use flow control, set this buffer size to at least 1024 bytes. // :[0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] -//#define RX_BUFFER_SIZE 1024 +#define RX_BUFFER_SIZE 32 #if RX_BUFFER_SIZE >= 1024 // Enable to have the controller send XON/XOFF control characters to @@ -2173,7 +2173,7 @@ * Currently handles M108, M112, M410, M876 * NOTE: Not yet implemented for all platforms. */ -//#define EMERGENCY_PARSER +#define EMERGENCY_PARSER /** * Realtime Reporting (requires EMERGENCY_PARSER) @@ -2350,14 +2350,14 @@ * * Enable PARK_HEAD_ON_PAUSE to add the G-code M125 Pause and Park. */ -//#define ADVANCED_PAUSE_FEATURE +#define ADVANCED_PAUSE_FEATURE #if ENABLED(ADVANCED_PAUSE_FEATURE) #define PAUSE_PARK_RETRACT_FEEDRATE 60 // (mm/s) Initial retract feedrate. #define PAUSE_PARK_RETRACT_LENGTH 2 // (mm) Initial retract. // This short retract is done immediately, before parking the nozzle. - #define FILAMENT_CHANGE_UNLOAD_FEEDRATE 10 // (mm/s) Unload filament feedrate. This can be pretty fast. + #define FILAMENT_CHANGE_UNLOAD_FEEDRATE 20 // (mm/s) Unload filament feedrate. This can be pretty fast. #define FILAMENT_CHANGE_UNLOAD_ACCEL 25 // (mm/s^2) Lower acceleration may allow a faster feedrate. - #define FILAMENT_CHANGE_UNLOAD_LENGTH 100 // (mm) The length of filament for a complete unload. + #define FILAMENT_CHANGE_UNLOAD_LENGTH 0 // (mm) The length of filament for a complete unload. // For Bowden, the full length of the tube and nozzle. // For direct drive, the full length of the nozzle. // Set to 0 for manual unloading. @@ -2371,7 +2371,7 @@ // For direct drive, the full length of the nozzle. //#define ADVANCED_PAUSE_CONTINUOUS_PURGE // Purge continuously up to the purge length until interrupted. #define ADVANCED_PAUSE_PURGE_FEEDRATE 3 // (mm/s) Extrude feedrate (after loading). Should be slower than load feedrate. - #define ADVANCED_PAUSE_PURGE_LENGTH 50 // (mm) Length to extrude after loading. + #define ADVANCED_PAUSE_PURGE_LENGTH 10 // (mm) Length to extrude after loading. // Set to 0 for manual extrusion. // Filament can be extruded repeatedly from the Filament Change menu // until extrusion is consistent, and to purge old filament. @@ -2384,11 +2384,11 @@ #define FILAMENT_UNLOAD_PURGE_LENGTH 8 // (mm) An unretract is done, then this length is purged. #define FILAMENT_UNLOAD_PURGE_FEEDRATE 25 // (mm/s) feedrate to purge before unload - #define PAUSE_PARK_NOZZLE_TIMEOUT 45 // (seconds) Time limit before the nozzle is turned off for safety. + #define PAUSE_PARK_NOZZLE_TIMEOUT 300 // (seconds) Time limit before the nozzle is turned off for safety. #define FILAMENT_CHANGE_ALERT_BEEPS 10 // Number of alert beeps to play when a response is needed. #define PAUSE_PARK_NO_STEPPER_TIMEOUT // Enable for XYZ steppers to stay powered on during filament change. - //#define PARK_HEAD_ON_PAUSE // Park the nozzle during pause and filament change. + #define PARK_HEAD_ON_PAUSE // Park the nozzle during pause and filament change. //#define HOME_BEFORE_FILAMENT_CHANGE // If needed, home before parking for filament change //#define FILAMENT_LOAD_UNLOAD_GCODES // Add M701/M702 Load/Unload G-codes, plus Load/Unload in the LCD Prepare menu. @@ -2909,11 +2909,11 @@ #if EITHER(SENSORLESS_HOMING, SENSORLESS_PROBING) // TMC2209: 0...255. TMC2130: -64...63 - #define X_STALL_SENSITIVITY 8 + #define X_STALL_SENSITIVITY 20 #define X2_STALL_SENSITIVITY X_STALL_SENSITIVITY - #define Y_STALL_SENSITIVITY 8 - #define Y2_STALL_SENSITIVITY Y_STALL_SENSITIVITY - //#define Z_STALL_SENSITIVITY 8 + #define Y_STALL_SENSITIVITY 20 + //#define Y2_STALL_SENSITIVITY Y_STALL_SENSITIVITY + #define Z_STALL_SENSITIVITY 100 //#define Z2_STALL_SENSITIVITY Z_STALL_SENSITIVITY //#define Z3_STALL_SENSITIVITY Z_STALL_SENSITIVITY //#define Z4_STALL_SENSITIVITY Z_STALL_SENSITIVITY @@ -3788,9 +3788,9 @@ * Host Prompt Support enables Marlin to use the host for user prompts so * filament runout and other processes can be managed from the host side. */ -//#define HOST_ACTION_COMMANDS +#define HOST_ACTION_COMMANDS #if ENABLED(HOST_ACTION_COMMANDS) - //#define HOST_PROMPT_SUPPORT + #define HOST_PROMPT_SUPPORT //#define HOST_START_MENU_ITEM // Add a menu item that tells the host to start #endif diff --git a/Marlin/src/MarlinCore.cpp b/Marlin/src/MarlinCore.cpp index b3870c8d11..6c1b4a2ce4 100644 --- a/Marlin/src/MarlinCore.cpp +++ b/Marlin/src/MarlinCore.cpp @@ -59,6 +59,7 @@ #include "gcode/parser.h" #include "gcode/queue.h" +#include "feature/runout.h" #include "feature/pause.h" #include "sd/cardreader.h" @@ -72,6 +73,7 @@ #include "../snapmaker/module/filament_sensor.h" #include "../snapmaker/module/print_control.h" #include "../snapmaker/module/system.h" + #if HAS_TOUCH_BUTTONS #include "lcd/touch/touch_buttons.h" #endif @@ -828,7 +830,15 @@ void idle(bool no_stepper_sleep/*=false*/) { (void)check_tool_sensor_stats(active_extruder, true); // Handle filament runout sensors - TERN_(HAS_FILAMENT_SENSOR, runout.run()); + TERN_(HAS_FILAMENT_SENSOR, { + if (!is_hmi_printing && marlin_state != MF_INITIALIZING) { // OctoPrint: Custom runout detection + HOTEND_LOOP() { + if (filament_sensor.is_trigger(e) && !FilamentMonitor::is_triggered(e)) { + FilamentMonitor::runout_detected(e); + } + } + } + }); // Run HAL idle tasks TERN_(HAL_IDLETASK, HAL_idletask()); @@ -1676,6 +1686,8 @@ AT_END_OF_TEXT void setup() { ui.check_touch_calibration(); #endif + is_hmi_printing = false; // Default to OctoPrint/serial + marlin_state = MF_RUNNING; SETUP_LOG("setup() completed."); diff --git a/Marlin/src/feature/mmu/mmu2.cpp b/Marlin/src/feature/mmu/mmu2.cpp index 8a4f5ae071..5cc3c8f644 100644 --- a/Marlin/src/feature/mmu/mmu2.cpp +++ b/Marlin/src/feature/mmu/mmu2.cpp @@ -770,8 +770,12 @@ bool MMU2::get_response() { * Wait for response and deal with timeout if necessary */ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { - - constexpr xyz_pos_t park_point = NOZZLE_PARK_POINT; + xyz_pos_t park_point; + if (active_extruder == 0) { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T0}; + } else { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T1}; + } bool response = false; mmu_print_saved = false; xyz_pos_t resume_position; @@ -795,8 +799,15 @@ void MMU2::manage_response(const bool move_axes, const bool turn_off_nozzle) { resume_hotend_temp = thermalManager.degTargetHotend(active_extruder); resume_position = current_position; - if (move_axes && all_axes_homed()) - nozzle.park(0, park_point /*= NOZZLE_PARK_POINT*/); + if (move_axes && all_axes_homed()) { + #if ENABLED(DUAL_X_CARRIAGE) + if (active_extruder == 1) endstops.enable_globally(false); + #endif + nozzle.park(0, park_point); + #if ENABLED(DUAL_X_CARRIAGE) + if (active_extruder == 1) endstops.enable_globally(true); + #endif + } if (turn_off_nozzle) thermalManager.setTargetHotend(0, active_extruder); diff --git a/Marlin/src/feature/pause.cpp b/Marlin/src/feature/pause.cpp index 2bd3033808..7f7ef718c8 100644 --- a/Marlin/src/feature/pause.cpp +++ b/Marlin/src/feature/pause.cpp @@ -25,653 +25,360 @@ * This may be combined with related G-codes if features are consolidated. */ -#include "../inc/MarlinConfigPre.h" - -#if ENABLED(ADVANCED_PAUSE_FEATURE) - -//#define DEBUG_PAUSE_RESUME - -#include "../MarlinCore.h" -#include "../gcode/gcode.h" -#include "../module/motion.h" -#include "../module/planner.h" -#include "../module/stepper.h" -#include "../module/printcounter.h" -#include "../module/temperature.h" - -#if ENABLED(FWRETRACT) - #include "fwretract.h" -#endif - -#if HAS_FILAMENT_SENSOR - #include "runout.h" -#endif - -#if ENABLED(HOST_ACTION_COMMANDS) - #include "host_actions.h" -#endif - -#if ENABLED(EXTENSIBLE_UI) - #include "../lcd/extui/ui_api.h" -#endif - -#include "../lcd/marlinui.h" - -#if HAS_BUZZER - #include "../libs/buzzer.h" -#endif - -#if ENABLED(POWER_LOSS_RECOVERY) - #include "powerloss.h" -#endif - -#include "../libs/nozzle.h" -#include "pause.h" - -#define DEBUG_OUT ENABLED(DEBUG_PAUSE_RESUME) -#include "../core/debug_out.h" - -// private: - -static xyze_pos_t resume_position; - -#if M600_PURGE_MORE_RESUMABLE - PauseMenuResponse pause_menu_response; - PauseMode pause_mode = PAUSE_MODE_PAUSE_PRINT; -#endif - -fil_change_settings_t fc_settings[EXTRUDERS]; - -#if ENABLED(SDSUPPORT) - #include "../sd/cardreader.h" -#endif - -#if ENABLED(EMERGENCY_PARSER) - #define _PMSG(L) L##_M108 -#else - #define _PMSG(L) L##_LCD -#endif - -#if HAS_BUZZER - static void impatient_beep(const int8_t max_beep_count, const bool restart=false) { - - if (TERN0(HAS_LCD_MENU, pause_mode == PAUSE_MODE_PAUSE_PRINT)) return; - - static millis_t next_buzz = 0; - static int8_t runout_beep = 0; - - if (restart) next_buzz = runout_beep = 0; - - const bool always = max_beep_count < 0; - - const millis_t ms = millis(); - if (ELAPSED(ms, next_buzz)) { - if (always || runout_beep < max_beep_count + 5) { // Only beep as long as we're supposed to - next_buzz = ms + ((always || runout_beep < max_beep_count) ? 1000 : 500); - BUZZ(50, 880 - (runout_beep & 1) * 220); - runout_beep++; - } - } - } - inline void first_impatient_beep(const int8_t max_beep_count) { impatient_beep(max_beep_count, true); } -#else - inline void impatient_beep(const int8_t, const bool=false) {} - inline void first_impatient_beep(const int8_t) {} -#endif - -/** - * Ensure a safe temperature for extrusion - * - * - Fail if the TARGET temperature is too low - * - Display LCD placard with temperature status - * - Return when heating is done or aborted - * - * Returns 'true' if heating was completed, 'false' for abort - */ -static bool ensure_safe_temperature(const bool wait=true, const PauseMode mode=PAUSE_MODE_SAME) { - DEBUG_SECTION(est, "ensure_safe_temperature", true); - DEBUG_ECHOLNPAIR("... wait:", wait, " mode:", mode); - - #if ENABLED(PREVENT_COLD_EXTRUSION) - if (!DEBUGGING(DRYRUN) && thermalManager.targetTooColdToExtrude(active_extruder)) - thermalManager.setTargetHotend(thermalManager.extrude_min_temp, active_extruder); - #endif - - ui.pause_show_message(PAUSE_MESSAGE_HEATING, mode); UNUSED(mode); - - if (wait) return thermalManager.wait_for_hotend(active_extruder); - - // Allow interruption by Emergency Parser M108 - wait_for_heatup = TERN1(PREVENT_COLD_EXTRUSION, !thermalManager.allow_cold_extrude); - while (wait_for_heatup && ABS(thermalManager.wholeDegHotend(active_extruder) - thermalManager.degTargetHotend(active_extruder)) > (TEMP_WINDOW)) - idle(); - wait_for_heatup = false; - - #if ENABLED(PREVENT_COLD_EXTRUSION) - // A user can cancel wait-for-heating with M108 - if (!DEBUGGING(DRYRUN) && thermalManager.targetTooColdToExtrude(active_extruder)) { - SERIAL_ECHO_MSG(STR_ERR_HOTEND_TOO_COLD); - return false; - } - #endif - - return true; -} - -/** - * Load filament into the hotend - * - * - Fail if the a safe temperature was not reached - * - If pausing for confirmation, wait for a click or M108 - * - Show "wait for load" placard - * - Load and purge filament - * - Show "Purge more" / "Continue" menu - * - Return when "Continue" is selected - * - * Returns 'true' if load was completed, 'false' for abort - */ -bool load_filament(const_float_t slow_load_length/*=0*/, const_float_t fast_load_length/*=0*/, const_float_t purge_length/*=0*/, const int8_t max_beep_count/*=0*/, - const bool show_lcd/*=false*/, const bool pause_for_user/*=false*/, - const PauseMode mode/*=PAUSE_MODE_PAUSE_PRINT*/ - DXC_ARGS -) { - DEBUG_SECTION(lf, "load_filament", true); - DEBUG_ECHOLNPAIR("... slowlen:", slow_load_length, " fastlen:", fast_load_length, " purgelen:", purge_length, " maxbeep:", max_beep_count, " showlcd:", show_lcd, " pauseforuser:", pause_for_user, " pausemode:", mode DXC_SAY); - - if (!ensure_safe_temperature(false, mode)) { - if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_STATUS, mode); - return false; - } - - if (pause_for_user) { - if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_INSERT, mode); - SERIAL_ECHO_MSG(_PMSG(STR_FILAMENT_CHANGE_INSERT)); - - first_impatient_beep(max_beep_count); - - KEEPALIVE_STATE(PAUSED_FOR_USER); - wait_for_user = true; // LCD click or M108 will clear this - #if ENABLED(HOST_PROMPT_SUPPORT) - const char tool = '0' + TERN0(MULTI_FILAMENT_SENSOR, active_extruder); - host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Load Filament T"), tool, CONTINUE_STR); - #endif - - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(PSTR("Load Filament"))); - - while (wait_for_user) { - impatient_beep(max_beep_count); - idle_no_sleep(); - } - } - - if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_LOAD, mode); - - #if ENABLED(DUAL_X_CARRIAGE) - const int8_t saved_ext = active_extruder; - const bool saved_ext_dup_mode = extruder_duplication_enabled; - set_duplication_enabled(false, DXC_ext); - #endif - - // Slow Load filament - if (slow_load_length) unscaled_e_move(slow_load_length, FILAMENT_CHANGE_SLOW_LOAD_FEEDRATE); - - // Fast Load Filament - if (fast_load_length) { - #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0 - const float saved_acceleration = planner.settings.retract_acceleration; - planner.settings.retract_acceleration = FILAMENT_CHANGE_FAST_LOAD_ACCEL; - #endif - - unscaled_e_move(fast_load_length, FILAMENT_CHANGE_FAST_LOAD_FEEDRATE); - - #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0 - planner.settings.retract_acceleration = saved_acceleration; - #endif - } - - #if ENABLED(DUAL_X_CARRIAGE) // Tie the two extruders movement back together. - set_duplication_enabled(saved_ext_dup_mode, saved_ext); - #endif - - #if ENABLED(ADVANCED_PAUSE_CONTINUOUS_PURGE) - - if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_PURGE); - - TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Filament Purging..."), CONTINUE_STR)); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(PSTR("Filament Purging..."))); - wait_for_user = true; // A click or M108 breaks the purge_length loop - for (float purge_count = purge_length; purge_count > 0 && wait_for_user; --purge_count) - unscaled_e_move(1, ADVANCED_PAUSE_PURGE_FEEDRATE); - wait_for_user = false; - - #else - - do { - if (purge_length > 0) { - // "Wait for filament purge" - if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_PURGE); - - // Extrude filament to get into hotend - unscaled_e_move(purge_length, ADVANCED_PAUSE_PURGE_FEEDRATE); - } - - TERN_(HOST_PROMPT_SUPPORT, filament_load_host_prompt()); // Initiate another host prompt. - - #if M600_PURGE_MORE_RESUMABLE - if (show_lcd) { - // Show "Purge More" / "Resume" menu and wait for reply - KEEPALIVE_STATE(PAUSED_FOR_USER); - wait_for_user = false; - #if HAS_LCD_MENU - ui.pause_show_message(PAUSE_MESSAGE_OPTION); // Also sets PAUSE_RESPONSE_WAIT_FOR - #else - pause_menu_response = PAUSE_RESPONSE_WAIT_FOR; - #endif - while (pause_menu_response == PAUSE_RESPONSE_WAIT_FOR) idle_no_sleep(); - } - #endif - - // Keep looping if "Purge More" was selected - } while (TERN0(M600_PURGE_MORE_RESUMABLE, show_lcd && pause_menu_response == PAUSE_RESPONSE_EXTRUDE_MORE)); - - #endif - TERN_(HOST_PROMPT_SUPPORT, host_action_prompt_end()); - - return true; -} - -/** - * Disabling E steppers for manual filament change should be fine - * as long as users don't spin the E motor ridiculously fast and - * send current back to their board, potentially frying it. - */ -inline void disable_active_extruder() { - #if HAS_E_STEPPER_ENABLE - disable_e_stepper(active_extruder); - safe_delay(100); - #endif -} - -/** - * Unload filament from the hotend - * - * - Fail if the a safe temperature was not reached - * - Show "wait for unload" placard - * - Retract, pause, then unload filament - * - Disable E stepper (on most machines) - * - * Returns 'true' if unload was completed, 'false' for abort - */ -bool unload_filament(const_float_t unload_length, const bool show_lcd/*=false*/, - const PauseMode mode/*=PAUSE_MODE_PAUSE_PRINT*/ - #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) - , const_float_t mix_multiplier/*=1.0*/ - #endif -) { - DEBUG_SECTION(uf, "unload_filament", true); - DEBUG_ECHOLNPAIR("... unloadlen:", unload_length, " showlcd:", show_lcd, " mode:", mode - #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) - , " mixmult:", mix_multiplier - #endif - ); - - #if !BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) - constexpr float mix_multiplier = 1.0f; - #endif - - if (!ensure_safe_temperature(false, mode)) { - if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_STATUS); - return false; - } - - if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_UNLOAD, mode); - - // Retract filament - unscaled_e_move(-(FILAMENT_UNLOAD_PURGE_RETRACT) * mix_multiplier, (PAUSE_PARK_RETRACT_FEEDRATE) * mix_multiplier); - - // Wait for filament to cool - safe_delay(FILAMENT_UNLOAD_PURGE_DELAY); - - // Quickly purge - unscaled_e_move((FILAMENT_UNLOAD_PURGE_RETRACT + FILAMENT_UNLOAD_PURGE_LENGTH) * mix_multiplier, - (FILAMENT_UNLOAD_PURGE_FEEDRATE) * mix_multiplier); - - // Unload filament - #if FILAMENT_CHANGE_UNLOAD_ACCEL > 0 - const float saved_acceleration = planner.settings.retract_acceleration; - planner.settings.retract_acceleration = FILAMENT_CHANGE_UNLOAD_ACCEL; - #endif - - unscaled_e_move(unload_length * mix_multiplier, (FILAMENT_CHANGE_UNLOAD_FEEDRATE) * mix_multiplier); - - #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0 - planner.settings.retract_acceleration = saved_acceleration; - #endif - - // Disable the Extruder for manual change - disable_active_extruder(); - - return true; -} - -// public: - -/** - * Pause procedure - * - * - Abort if already paused - * - Send host action for pause, if configured - * - Abort if TARGET temperature is too low - * - Display "wait for start of filament change" (if a length was specified) - * - Initial retract, if current temperature is hot enough - * - Park the nozzle at the given position - * - Call unload_filament (if a length was specified) - * - * Return 'true' if pause was completed, 'false' for abort - */ -uint8_t did_pause_print = 0; - -bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool show_lcd/*=false*/, const_float_t unload_length/*=0*/ DXC_ARGS) { - DEBUG_SECTION(pp, "pause_print", true); - DEBUG_ECHOLNPAIR("... park.x:", park_point.x, " y:", park_point.y, " z:", park_point.z, " unloadlen:", unload_length, " showlcd:", show_lcd DXC_SAY); - - UNUSED(show_lcd); - - if (did_pause_print) return false; // already paused - - #if ENABLED(HOST_ACTION_COMMANDS) - #ifdef ACTION_ON_PAUSED - host_action_paused(); - #elif defined(ACTION_ON_PAUSE) - host_action_pause(); - #endif - #endif - - TERN_(HOST_PROMPT_SUPPORT, host_prompt_open(PROMPT_INFO, PSTR("Pause"), DISMISS_STR)); - - // Indicate that the printer is paused - ++did_pause_print; - - // Pause the print job and timer - #if ENABLED(SDSUPPORT) - const bool was_sd_printing = IS_SD_PRINTING(); - if (was_sd_printing) { - card.pauseSDPrint(); - ++did_pause_print; // Indicate SD pause also - } - #endif - - print_job_timer.pause(); - - // Save current position - resume_position = current_position; - - // Will the nozzle be parking? - const bool do_park = !axes_should_home(); - - #if ENABLED(POWER_LOSS_RECOVERY) - // Save PLR info in case the power goes out while parked - const float park_raise = do_park ? nozzle.park_mode_0_height(park_point.z) - current_position.z : POWER_LOSS_ZRAISE; - if (was_sd_printing && recovery.enabled) recovery.save(true, park_raise, do_park); - #endif - - // Wait for buffered blocks to complete - planner.synchronize(); - - #if ENABLED(ADVANCED_PAUSE_FANS_PAUSE) && HAS_FAN - thermalManager.set_fans_paused(true); - #endif - - // Initial retract before move to filament change position - if (retract && thermalManager.hotEnoughToExtrude(active_extruder)) { - DEBUG_ECHOLNPAIR("... retract:", retract); - unscaled_e_move(retract, PAUSE_PARK_RETRACT_FEEDRATE); - } - - // If axes don't need to home then the nozzle can park - if (do_park) nozzle.park(0, park_point); // Park the nozzle by doing a Minimum Z Raise followed by an XY Move - - #if ENABLED(DUAL_X_CARRIAGE) - const int8_t saved_ext = active_extruder; - const bool saved_ext_dup_mode = extruder_duplication_enabled; - set_duplication_enabled(false, DXC_ext); - #endif - - // Unload the filament, if specified - if (unload_length) - unload_filament(unload_length, show_lcd, PAUSE_MODE_CHANGE_FILAMENT); - - #if ENABLED(DUAL_X_CARRIAGE) - set_duplication_enabled(saved_ext_dup_mode, saved_ext); - #endif - - // Disable the Extruder for manual change - disable_active_extruder(); - - return true; -} - -/** - * For Paused Print: - * - Show "Press button (or M108) to resume" - * - * For Filament Change: - * - Show "Insert filament and press button to continue" - * - * - Wait for a click before returning - * - Heaters can time out and must reheat before continuing - * - * Used by M125 and M600 - */ - -void show_continue_prompt(const bool is_reload) { - DEBUG_SECTION(scp, "pause_print", true); - DEBUG_ECHOLNPAIR("... is_reload:", is_reload); - - ui.pause_show_message(is_reload ? PAUSE_MESSAGE_INSERT : PAUSE_MESSAGE_WAITING); - SERIAL_ECHO_START(); - SERIAL_ECHOPGM_P(is_reload ? PSTR(_PMSG(STR_FILAMENT_CHANGE_INSERT) "\n") : PSTR(_PMSG(STR_FILAMENT_CHANGE_WAIT) "\n")); -} - -void wait_for_confirmation(const bool is_reload/*=false*/, const int8_t max_beep_count/*=0*/ DXC_ARGS) { - DEBUG_SECTION(wfc, "wait_for_confirmation", true); - DEBUG_ECHOLNPAIR("... is_reload:", is_reload, " maxbeep:", max_beep_count DXC_SAY); - - bool nozzle_timed_out = false; - - show_continue_prompt(is_reload); - - first_impatient_beep(max_beep_count); - - // Start the heater idle timers - const millis_t nozzle_timeout = SEC_TO_MS(PAUSE_PARK_NOZZLE_TIMEOUT); - - HOTEND_LOOP() thermalManager.heater_idle[e].start(nozzle_timeout); - - #if ENABLED(DUAL_X_CARRIAGE) - const int8_t saved_ext = active_extruder; - const bool saved_ext_dup_mode = extruder_duplication_enabled; - set_duplication_enabled(false, DXC_ext); - #endif - - // Wait for filament insert by user and press button - KEEPALIVE_STATE(PAUSED_FOR_USER); - TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, GET_TEXT(MSG_NOZZLE_PARKED), CONTINUE_STR)); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(GET_TEXT(MSG_NOZZLE_PARKED))); - wait_for_user = true; // LCD click or M108 will clear this - while (wait_for_user) { - impatient_beep(max_beep_count); - - // If the nozzle has timed out... - if (!nozzle_timed_out) - HOTEND_LOOP() nozzle_timed_out |= thermalManager.heater_idle[e].timed_out; - - // Wait for the user to press the button to re-heat the nozzle, then - // 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); - SERIAL_ECHO_MSG(_PMSG(STR_FILAMENT_CHANGE_HEAT)); - - TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, GET_TEXT(MSG_HEATER_TIMEOUT), GET_TEXT(MSG_REHEAT))); - - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(GET_TEXT(MSG_HEATER_TIMEOUT))); - - wait_for_user_response(0, true); // Wait for LCD click or M108 - - TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_INFO, GET_TEXT(MSG_REHEATING))); - - TERN_(EXTENSIBLE_UI, ExtUI::onStatusChanged_P(GET_TEXT(MSG_REHEATING))); - - // Re-enable the heaters if they timed out - HOTEND_LOOP() thermalManager.reset_hotend_idle_timer(e); - - // Wait for the heaters to reach the target temperatures - ensure_safe_temperature(false); - - // Show the prompt to continue - show_continue_prompt(is_reload); - - // Start the heater idle timers - const millis_t nozzle_timeout = SEC_TO_MS(PAUSE_PARK_NOZZLE_TIMEOUT); - - HOTEND_LOOP() thermalManager.heater_idle[e].start(nozzle_timeout); - TERN_(HOST_PROMPT_SUPPORT, host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Reheat Done"), CONTINUE_STR)); - TERN_(EXTENSIBLE_UI, ExtUI::onUserConfirmRequired_P(PSTR("Reheat finished."))); - wait_for_user = true; - nozzle_timed_out = false; - - first_impatient_beep(max_beep_count); - } - idle_no_sleep(); - } - #if ENABLED(DUAL_X_CARRIAGE) - set_duplication_enabled(saved_ext_dup_mode, saved_ext); - #endif -} - -/** - * Resume or Start print procedure - * - * - If not paused, do nothing and return - * - Reset heater idle timers - * - Load filament if specified, but only if: - * - a nozzle timed out, or - * - the nozzle is already heated. - * - Display "wait for print to resume" - * - Retract to prevent oozing - * - Move the nozzle back to resume_position - * - Unretract - * - Re-prime the nozzle... - * - FWRETRACT: Recover/prime from the prior G10. - * - !FWRETRACT: Retract by resume_position.e, if negative. - * Not sure how this logic comes into use. - * - Sync the planner E to resume_position.e - * - Send host action for resume, if configured - * - Resume the current SD print job, if any - */ -void resume_print(const_float_t slow_load_length/*=0*/, const_float_t fast_load_length/*=0*/, const_float_t purge_length/*=ADVANCED_PAUSE_PURGE_LENGTH*/, const int8_t max_beep_count/*=0*/, const celsius_t targetTemp/*=0*/ DXC_ARGS) { - DEBUG_SECTION(rp, "resume_print", true); - DEBUG_ECHOLNPAIR("... slowlen:", slow_load_length, " fastlen:", fast_load_length, " purgelen:", purge_length, " maxbeep:", max_beep_count, " targetTemp:", targetTemp DXC_SAY); - - /* - SERIAL_ECHOLNPAIR( - "start of resume_print()\ndual_x_carriage_mode:", dual_x_carriage_mode, - "\nextruder_duplication_enabled:", extruder_duplication_enabled, - "\nactive_extruder:", active_extruder, - "\n" - ); - //*/ - - if (!did_pause_print) return; - - // Re-enable the heaters if they timed out - bool nozzle_timed_out = false; - HOTEND_LOOP() { - nozzle_timed_out |= thermalManager.heater_idle[e].timed_out; - thermalManager.reset_hotend_idle_timer(e); - } - - if (targetTemp > thermalManager.degTargetHotend(active_extruder)) - thermalManager.setTargetHotend(targetTemp, active_extruder); - - // Load the new filament - load_filament(slow_load_length, fast_load_length, purge_length, max_beep_count, true, nozzle_timed_out, PAUSE_MODE_SAME DXC_PASS); - - if (targetTemp > 0) { - thermalManager.setTargetHotend(targetTemp, active_extruder); - thermalManager.wait_for_hotend(active_extruder, false); - } - - ui.pause_show_message(PAUSE_MESSAGE_RESUME); - - // Check Temperature before moving hotend - ensure_safe_temperature(); - - // Retract to prevent oozing - unscaled_e_move(-(PAUSE_PARK_RETRACT_LENGTH), feedRate_t(PAUSE_PARK_RETRACT_FEEDRATE)); - - if (!axes_should_home()) { - // Move XY back to saved position - destination.set(resume_position.x, resume_position.y, current_position.z, current_position.e); - prepare_internal_move_to_destination(NOZZLE_PARK_XY_FEEDRATE); - - // Move Z back to saved position - destination.z = resume_position.z; - prepare_internal_move_to_destination(NOZZLE_PARK_Z_FEEDRATE); - } - - // Unretract - unscaled_e_move(PAUSE_PARK_RETRACT_LENGTH, feedRate_t(PAUSE_PARK_RETRACT_FEEDRATE)); - - // Intelligent resuming - #if ENABLED(FWRETRACT) - // If retracted before goto pause - if (fwretract.retracted[active_extruder]) - unscaled_e_move(-fwretract.settings.retract_length, fwretract.settings.retract_feedrate_mm_s); - #endif - - // If resume_position is negative - if (resume_position.e < 0) unscaled_e_move(resume_position.e, feedRate_t(PAUSE_PARK_RETRACT_FEEDRATE)); - #if ADVANCED_PAUSE_RESUME_PRIME != 0 - unscaled_e_move(ADVANCED_PAUSE_RESUME_PRIME, feedRate_t(ADVANCED_PAUSE_PURGE_FEEDRATE)); - #endif - - // Now all extrusion positions are resumed and ready to be confirmed - // Set extruder to saved position - planner.set_e_position_mm((destination.e = current_position.e = resume_position.e)); - - ui.pause_show_message(PAUSE_MESSAGE_STATUS); - - #ifdef ACTION_ON_RESUMED + #include "../inc/MarlinConfigPre.h" + + #if ENABLED(ADVANCED_PAUSE_FEATURE) && !IS_HMI_PRINTING + + #include "../MarlinCore.h" + #include "../gcode/gcode.h" + #include "../module/motion.h" + #include "../module/planner.h" + #include "../module/stepper.h" + #include "../module/printcounter.h" + #include "../module/temperature.h" + + #if ENABLED(FWRETRACT) + #include "fwretract.h" + #endif + + #if HAS_FILAMENT_SENSOR + #include "runout.h" + #endif + + #if ENABLED(HOST_ACTION_COMMANDS) + #include "host_actions.h" + #endif + + #if ENABLED(EXTENSIBLE_UI) + #include "../lcd/extui/ui_api.h" + #endif + + #include "../lcd/marlinui.h" + + #if HAS_BUZZER + #include "../libs/buzzer.h" + #endif + + #if ENABLED(POWER_LOSS_RECOVERY) + #include "powerloss.h" + #endif + + #include "../libs/nozzle.h" + #include "pause.h" + + #define DEBUG_OUT ENABLED(DEBUG_PAUSE_RESUME) + #include "../core/debug_out.h" + + // Private variables + static xyze_pos_t resume_position; + + #if M600_PURGE_MORE_RESUMABLE + PauseMenuResponse pause_menu_response; + PauseMode pause_mode = PAUSE_MODE_PAUSE_PRINT; + #endif + + fil_change_settings_t fc_settings[EXTRUDERS]; + + #if ENABLED(SDSUPPORT) + #include "../sd/cardreader.h" + #endif + + #if ENABLED(EMERGENCY_PARSER) + #define _PMSG(L) L##_M108 + #else + #define _PMSG(L) L##_LCD + #endif + + #if HAS_BUZZER + static void impatient_beep(const int8_t max_beep_count, const bool restart = false) { + if (TERN0(HAS_LCD_MENU, pause_mode == PAUSE_MODE_PAUSE_PRINT)) return; + + static millis_t next_buzz = 0; + static int8_t runout_beep = 0; + + if (restart) next_buzz = runout_beep = 0; + + const bool always = max_beep_count < 0; + const millis_t ms = millis(); + if (ELAPSED(ms, next_buzz)) { + if (always || runout_beep < max_beep_count + 5) { + next_buzz = ms + ((always || runout_beep < max_beep_count) ? 1000 : 500); + BUZZ(50, 880 - (runout_beep & 1) * 220); + runout_beep++; + } + } + } + inline void first_impatient_beep(const int8_t max_beep_count) { impatient_beep(max_beep_count, true); } + #else + inline void impatient_beep(const int8_t, const bool = false) {} + inline void first_impatient_beep(const int8_t) {} + #endif + + bool ensure_safe_temperature(const bool wait, const PauseMode mode) { + #if ENABLED(PREVENT_COLD_EXTRUSION) + if (!DEBUGGING(DRYRUN) && thermalManager.targetTooColdToExtrude(active_extruder)) + thermalManager.setTargetHotend(thermalManager.extrude_min_temp, active_extruder); + #endif + + ui.pause_show_message(PAUSE_MESSAGE_HEATING, mode); // Unused by Snapmaker, but kept + return thermalManager.wait_for_hotend(active_extruder, wait); + } + + bool load_filament(const_float_t slow_load_length, const_float_t fast_load_length, const_float_t purge_length, const int8_t max_beep_count, + const bool show_lcd, const bool pause_for_user, const PauseMode mode DXC_ARGS) { + if (!ensure_safe_temperature(false, mode)) { + if (show_lcd) ui.pause_show_message(PAUSE_MESSAGE_STATUS, mode); + return false; + } + + if (pause_for_user) { + SERIAL_ECHO_MSG(_PMSG(STR_FILAMENT_CHANGE_INSERT)); + first_impatient_beep(max_beep_count); + KEEPALIVE_STATE(PAUSED_FOR_USER); + wait_for_user = true; + #if ENABLED(HOST_PROMPT_SUPPORT) + const char tool = '0' + TERN0(MULTI_FILAMENT_SENSOR, active_extruder); + host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Load Filament T"), tool, CONTINUE_STR); + #endif + while (wait_for_user) { + impatient_beep(max_beep_count); + idle_no_sleep(); + } + } + + if (slow_load_length) unscaled_e_move(slow_load_length, FILAMENT_CHANGE_SLOW_LOAD_FEEDRATE); + if (fast_load_length) unscaled_e_move(fast_load_length, FILAMENT_CHANGE_FAST_LOAD_FEEDRATE); + if (purge_length > 0) unscaled_e_move(purge_length, ADVANCED_PAUSE_PURGE_FEEDRATE); + + TERN_(HOST_PROMPT_SUPPORT, host_action_prompt_end()); + return true; + } + + inline void disable_active_extruder() { + #if HAS_E_STEPPER_ENABLE + disable_e_stepper(active_extruder); + safe_delay(100); + #endif + } + + bool unload_filament(const_float_t unload_length, const bool show_lcd, + const PauseMode mode + #if BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + , const_float_t mix_multiplier + #endif + ) { + #if !BOTH(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) + constexpr float mix_multiplier = 1.0f; + #endif + + if (!ensure_safe_temperature(false, mode)) return false; + + unscaled_e_move(-(FILAMENT_UNLOAD_PURGE_RETRACT) * mix_multiplier, (PAUSE_PARK_RETRACT_FEEDRATE) * mix_multiplier); + safe_delay(FILAMENT_UNLOAD_PURGE_DELAY); + unscaled_e_move((FILAMENT_UNLOAD_PURGE_RETRACT + FILAMENT_UNLOAD_PURGE_LENGTH) * mix_multiplier, + (FILAMENT_UNLOAD_PURGE_FEEDRATE) * mix_multiplier); + + #if FILAMENT_CHANGE_UNLOAD_ACCEL > 0 + const float saved_acceleration = planner.settings.retract_acceleration; + planner.settings.retract_acceleration = FILAMENT_CHANGE_UNLOAD_ACCEL; + #endif + + unscaled_e_move(unload_length * mix_multiplier, (FILAMENT_CHANGE_UNLOAD_FEEDRATE) * mix_multiplier); + + #if FILAMENT_CHANGE_FAST_LOAD_ACCEL > 0 + planner.settings.retract_acceleration = saved_acceleration; + #endif + + disable_active_extruder(); + return true; + } + + // Public variables and functions + uint8_t did_pause_print = 0; + bool is_m600_pause = false; + + bool pause_print(const_float_t retract, const xyz_pos_t &park_point, const bool show_lcd, const_float_t unload_length DXC_ARGS) { + if (did_pause_print) return false; + + #if ENABLED(HOST_ACTION_COMMANDS) + #ifdef ACTION_ON_PAUSED + host_action_paused(); + #elif defined(ACTION_ON_PAUSE) + host_action_pause(); + #endif + #endif + + #if ENABLED(HOST_PROMPT_SUPPORT) + host_prompt_open(PROMPT_INFO, PSTR("Pause"), DISMISS_STR); + #endif + + ++did_pause_print; + + #if ENABLED(SDSUPPORT) + const bool was_sd_printing = IS_SD_PRINTING(); + if (was_sd_printing) { + card.pauseSDPrint(); + ++did_pause_print; + } + #endif + + print_job_timer.pause(); + + resume_position = current_position; + const bool do_park = !axes_should_home(); + + #if ENABLED(POWER_LOSS_RECOVERY) + const float park_raise = do_park ? nozzle.park_mode_0_height(park_point.z) - current_position.z : POWER_LOSS_ZRAISE; + if (was_sd_printing && recovery.enabled) recovery.save(true, park_raise, do_park); + #endif + + planner.synchronize(); + + #if ENABLED(ADVANCED_PAUSE_FANS_PAUSE) && HAS_FAN + thermalManager.set_fans_paused(true); + #endif + + if (retract && thermalManager.hotEnoughToExtrude(active_extruder)) + unscaled_e_move(retract, PAUSE_PARK_RETRACT_FEEDRATE); + + if (do_park) nozzle.park(0, park_point); + + #if ENABLED(DUAL_X_CARRIAGE) + const int8_t saved_ext = active_extruder; + const bool saved_ext_dup_mode = extruder_duplication_enabled; + set_duplication_enabled(false, DXC_ext); + #endif + + if (unload_length) + unload_filament(unload_length, show_lcd, PAUSE_MODE_CHANGE_FILAMENT); + + #if ENABLED(DUAL_X_CARRIAGE) + set_duplication_enabled(saved_ext_dup_mode, saved_ext); + #endif + + disable_active_extruder(); + return true; + } + + void show_continue_prompt(const bool is_reload) { + ui.pause_show_message(is_reload ? PAUSE_MESSAGE_INSERT : PAUSE_MESSAGE_WAITING); + SERIAL_ECHO_START(); + SERIAL_ECHOPGM_P(is_reload ? PSTR(_PMSG(STR_FILAMENT_CHANGE_INSERT) "\n") : PSTR(_PMSG(STR_FILAMENT_CHANGE_WAIT) "\n")); + } + + void wait_for_confirmation(const bool is_reload, const int8_t max_beep_count DXC_ARGS) { + bool nozzle_timed_out = false; + const millis_t nozzle_timeout = SEC_TO_MS(PAUSE_PARK_NOZZLE_TIMEOUT); + HOTEND_LOOP() thermalManager.heater_idle[e].start(nozzle_timeout); + + KEEPALIVE_STATE(PAUSED_FOR_USER); + wait_for_user = true; + + show_continue_prompt(is_reload); + first_impatient_beep(max_beep_count); + + #if ENABLED(HOST_PROMPT_SUPPORT) + host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Nozzle Parked - Ready to Resume Print?"), CONTINUE_STR); + #endif + + while (wait_for_user) { + impatient_beep(max_beep_count); + HOTEND_LOOP() nozzle_timed_out |= thermalManager.heater_idle[e].timed_out; + if (nozzle_timed_out) { + #if ENABLED(HOST_PROMPT_SUPPORT) + host_action_prompt_end(); // Close "Nozzle Parked" prompt + host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Heater Timed Out - Reheat?"), PSTR("Reheat")); + #endif + SERIAL_ECHOLNPGM("Heater timed out - waiting for reheat confirmation"); + wait_for_user = true; + while (wait_for_user) idle_no_sleep(); + SERIAL_ECHOLNPGM("Reheating nozzle"); + HOTEND_LOOP() thermalManager.reset_hotend_idle_timer(e); + thermalManager.setTargetHotend(thermalManager.temp_hotend[active_extruder].target, active_extruder); + ensure_safe_temperature(false); + #if ENABLED(HOST_PROMPT_SUPPORT) + host_prompt_do(PROMPT_USER_CONTINUE, PSTR("Nozzle Parked - Ready to Resume Print?"), CONTINUE_STR); + #endif + HOTEND_LOOP() thermalManager.heater_idle[e].start(nozzle_timeout); + wait_for_user = true; + nozzle_timed_out = false; + first_impatient_beep(max_beep_count); + } + idle_no_sleep(); + } + } + + void resume_print(const_float_t slow_load_length, const_float_t fast_load_length, const_float_t purge_length, const int8_t max_beep_count, const celsius_t targetTemp DXC_ARGS) { + if (!did_pause_print) return; + + bool nozzle_timed_out = false; + HOTEND_LOOP() { + nozzle_timed_out |= thermalManager.heater_idle[e].timed_out; + thermalManager.reset_hotend_idle_timer(e); + } + + if (targetTemp > thermalManager.degTargetHotend(active_extruder)) + thermalManager.setTargetHotend(targetTemp, active_extruder); + + load_filament(slow_load_length, fast_load_length, purge_length, max_beep_count, true, nozzle_timed_out, PAUSE_MODE_SAME DXC_PASS); + + if (targetTemp > 0) { + thermalManager.setTargetHotend(targetTemp, active_extruder); + thermalManager.wait_for_hotend(active_extruder, false); + } + + ensure_safe_temperature(); + + unscaled_e_move(-(PAUSE_PARK_RETRACT_LENGTH), feedRate_t(PAUSE_PARK_RETRACT_FEEDRATE)); + + if (!axes_should_home()) { + destination.set(resume_position.x, resume_position.y, current_position.z, current_position.e); + prepare_internal_move_to_destination(NOZZLE_PARK_XY_FEEDRATE); + destination.z = resume_position.z; + prepare_internal_move_to_destination(NOZZLE_PARK_Z_FEEDRATE); + } + + unscaled_e_move(PAUSE_PARK_RETRACT_LENGTH, feedRate_t(PAUSE_PARK_RETRACT_FEEDRATE)); + + #if ENABLED(FWRETRACT) + if (fwretract.retracted[active_extruder]) + unscaled_e_move(-fwretract.settings.retract_length, fwretract.settings.retract_feedrate_mm_s); + #endif + + if (resume_position.e < 0) unscaled_e_move(resume_position.e, feedRate_t(PAUSE_PARK_RETRACT_FEEDRATE)); + #if ADVANCED_PAUSE_RESUME_PRIME != 0 + unscaled_e_move(ADVANCED_PAUSE_RESUME_PRIME, feedRate_t(ADVANCED_PAUSE_PURGE_FEEDRATE)); + #endif + + planner.set_e_position_mm((destination.e = current_position.e = resume_position.e)); + + #if defined(ACTION_ON_RESUME) + host_action_resume(); + #elif defined(ACTION_ON_RESUMED) host_action_resumed(); - #elif defined(ACTION_ON_RESUME) - host_action_resume(); - #endif - - --did_pause_print; - - TERN_(HOST_PROMPT_SUPPORT, host_prompt_open(PROMPT_INFO, PSTR("Resuming"), DISMISS_STR)); - - // Resume the print job timer if it was running - if (print_job_timer.isPaused()) print_job_timer.start(); - - #if ENABLED(SDSUPPORT) - if (did_pause_print) { - --did_pause_print; - card.startOrResumeFilePrinting(); - // Write PLR now to update the z axis value - TERN_(POWER_LOSS_RECOVERY, if (recovery.enabled) recovery.save(true)); - } #endif - - #if ENABLED(ADVANCED_PAUSE_FANS_PAUSE) && HAS_FAN - thermalManager.set_fans_paused(false); - #endif - - TERN_(HAS_FILAMENT_SENSOR, runout.reset()); - - TERN_(HAS_STATUS_MESSAGE, ui.reset_status()); - TERN_(HAS_LCD_MENU, ui.return_to_status()); -} - -#endif // ADVANCED_PAUSE_FEATURE + + --did_pause_print; + + #if ENABLED(HOST_PROMPT_SUPPORT) + host_prompt_open(PROMPT_INFO, PSTR("Resuming"), DISMISS_STR); + #endif + + if (print_job_timer.isPaused()) print_job_timer.start(); + + #if ENABLED(SDSUPPORT) + if (did_pause_print) { + --did_pause_print; + card.startOrResumeFilePrinting(); + TERN_(POWER_LOSS_RECOVERY, if (recovery.enabled) recovery.save(true)); + } + #endif + + #if ENABLED(ADVANCED_PAUSE_FANS_PAUSE) && HAS_FAN + thermalManager.set_fans_paused(false); + #endif + + TERN_(HAS_FILAMENT_SENSOR, runout.reset()); + } + + #endif // ADVANCED_PAUSE_FEATURE && !IS_HMI_PRINTING \ No newline at end of file diff --git a/Marlin/src/feature/pause.h b/Marlin/src/feature/pause.h index d2c45e44a5..9d5cacd9cb 100644 --- a/Marlin/src/feature/pause.h +++ b/Marlin/src/feature/pause.h @@ -33,7 +33,7 @@ typedef struct { #include "../inc/MarlinConfigPre.h" #if ENABLED(ADVANCED_PAUSE_FEATURE) - +extern bool is_m600_pause; #include "../libs/nozzle.h" enum PauseMode : char { @@ -129,6 +129,8 @@ bool unload_filament( #endif ); +bool ensure_safe_temperature(const bool wait=true, const PauseMode mode=PAUSE_MODE_SAME); + #else // !ADVANCED_PAUSE_FEATURE constexpr uint8_t did_pause_print = 0; diff --git a/Marlin/src/feature/runout.cpp b/Marlin/src/feature/runout.cpp index 531ca1081f..67385ed01a 100644 --- a/Marlin/src/feature/runout.cpp +++ b/Marlin/src/feature/runout.cpp @@ -24,122 +24,124 @@ * feature/runout.cpp - Runout sensor support */ -#include "../inc/MarlinConfigPre.h" - -#if HAS_FILAMENT_SENSOR - -#include "runout.h" - -FilamentMonitor runout; - -bool FilamentMonitorBase::enabled = true, - FilamentMonitorBase::filament_ran_out; // = false - -#if ENABLED(HOST_ACTION_COMMANDS) - bool FilamentMonitorBase::host_handling; // = false -#endif - -#if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) - #include "../module/tool_change.h" - #define DEBUG_OUT ENABLED(DEBUG_TOOLCHANGE_MIGRATION_FEATURE) - #include "../core/debug_out.h" -#endif - -#if HAS_FILAMENT_RUNOUT_DISTANCE - float RunoutResponseDelayed::runout_distance_mm = FILAMENT_RUNOUT_DISTANCE_MM; - volatile float RunoutResponseDelayed::runout_mm_countdown[NUM_RUNOUT_SENSORS]; - #if ENABLED(FILAMENT_MOTION_SENSOR) - uint8_t FilamentSensorEncoder::motion_detected; - #endif -#else - int8_t RunoutResponseDebounced::runout_count[NUM_RUNOUT_SENSORS]; // = 0 -#endif - -// -// Filament Runout event handler -// -#include "../MarlinCore.h" -#include "../feature/pause.h" -#include "../gcode/queue.h" - -#if ENABLED(HOST_ACTION_COMMANDS) - #include "host_actions.h" -#endif - -#if ENABLED(EXTENSIBLE_UI) - #include "../lcd/extui/ui_api.h" -#endif - -void event_filament_runout(const uint8_t extruder) { - - if (did_pause_print) return; // Action already in progress. Purge triggered repeated runout. - - #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) - if (migration.in_progress) { - DEBUG_ECHOLNPGM("Migration Already In Progress"); - return; // Action already in progress. Purge triggered repeated runout. - } - if (migration.automode) { - DEBUG_ECHOLNPGM("Migration Starting"); - if (extruder_migration()) return; - } - #endif - - TERN_(EXTENSIBLE_UI, ExtUI::onFilamentRunout(ExtUI::getTool(extruder))); - - #if ANY(HOST_PROMPT_SUPPORT, HOST_ACTION_COMMANDS, MULTI_FILAMENT_SENSOR) - const char tool = '0' + TERN0(MULTI_FILAMENT_SENSOR, extruder); - #endif - - //action:out_of_filament - #if ENABLED(HOST_PROMPT_SUPPORT) - host_action_prompt_begin(PROMPT_FILAMENT_RUNOUT, PSTR("FilamentRunout T"), tool); - host_action_prompt_show(); - #endif - - const bool run_runout_script = !runout.host_handling; - - #if ENABLED(HOST_ACTION_COMMANDS) - if (run_runout_script - && ( strstr(FILAMENT_RUNOUT_SCRIPT, "M600") - || strstr(FILAMENT_RUNOUT_SCRIPT, "M125") - || TERN0(ADVANCED_PAUSE_FEATURE, strstr(FILAMENT_RUNOUT_SCRIPT, "M25")) - ) - ) { - host_action_paused(false); - } - else { - // Legacy Repetier command for use until newer version supports standard dialog - // To be removed later when pause command also triggers dialog - #ifdef ACTION_ON_FILAMENT_RUNOUT - host_action(PSTR(ACTION_ON_FILAMENT_RUNOUT " T"), false); - SERIAL_CHAR(tool); - SERIAL_EOL(); - #endif - - host_action_pause(false); - } - SERIAL_ECHOPGM(" " ACTION_REASON_ON_FILAMENT_RUNOUT " "); - SERIAL_CHAR(tool); - SERIAL_EOL(); - #endif // HOST_ACTION_COMMANDS - - if (run_runout_script) { - #if MULTI_FILAMENT_SENSOR - char script[strlen(FILAMENT_RUNOUT_SCRIPT) + 1]; - sprintf_P(script, PSTR(FILAMENT_RUNOUT_SCRIPT), tool); - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - SERIAL_ECHOLNPAIR("Runout Command: ", script); - #endif - queue.inject(script); - #else - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - SERIAL_ECHOPGM("Runout Command: "); - SERIAL_ECHOLNPGM(FILAMENT_RUNOUT_SCRIPT); - #endif - queue.inject_P(PSTR(FILAMENT_RUNOUT_SCRIPT)); - #endif - } -} - -#endif // HAS_FILAMENT_SENSOR + #include "../inc/MarlinConfigPre.h" + #include "../../../snapmaker/module/print_control.h" + #include "../../../snapmaker/module/system.h" + + #if HAS_FILAMENT_SENSOR + + #include "runout.h" + #include "../../snapmaker/module/filament_sensor.h" // Custom ADC sensor + #include "../MarlinCore.h" + #include "../module/planner.h" // For planner.synchronize() + #include "../feature/pause.h" + #include "../gcode/queue.h" + + #if ENABLED(HOST_ACTION_COMMANDS) + #include "host_actions.h" + #endif + + #if ENABLED(EXTENSIBLE_UI) + #include "../lcd/extui/ui_api.h" + #endif + + FilamentMonitor runout; + + bool FilamentMonitorBase::enabled = true, + FilamentMonitorBase::filament_ran_out; + + #if ENABLED(HOST_ACTION_COMMANDS) + bool FilamentMonitorBase::host_handling; + #endif + + bool FilamentMonitor::triggered[NUM_RUNOUT_SENSORS] = { false }; + + void FilamentMonitor::setup() { + filament_sensor.init(); // Initialize your custom ADC sensor + reset(); + } + + void FilamentMonitor::reset() { + filament_ran_out = false; + ZERO(triggered); // Clear all triggered flags + } + + void FilamentMonitor::filament_present(const uint8_t extruder) { + triggered[extruder] = false; // Clear runout state for this extruder + filament_ran_out = false; // Reset global runout flag + filament_sensor.reset(extruder); // Reset your sensor’s internal state + } + + void FilamentMonitor::runout_detected(uint8_t e) { + if (is_hmi_printing) return; // Skip for HMI prints + if (is_triggered(e)) return; // Avoid re-triggering + SERIAL_ECHOLNPAIR("Runout detected on extruder ", e); + triggered[e] = true; + event_filament_runout(e); // Call the standard event handler + } + + void event_filament_runout(const uint8_t extruder) { + #if ENABLED(TOOLCHANGE_MIGRATION_FEATURE) + if (migration.in_progress) { + DEBUG_ECHOLNPGM("Migration Already In Progress"); + return; // Action already in progress. Purge triggered repeated runout. + } + if (migration.automode) { + DEBUG_ECHOLNPGM("Migration Starting"); + if (extruder_migration()) return; + } + #endif + + TERN_(EXTENSIBLE_UI, ExtUI::onFilamentRunout(ExtUI::getTool(extruder))); + + #if ANY(HOST_PROMPT_SUPPORT, HOST_ACTION_COMMANDS, MULTI_FILAMENT_SENSOR) + const char tool = '0' + TERN0(MULTI_FILAMENT_SENSOR, extruder); + #endif + + #if ENABLED(HOST_PROMPT_SUPPORT) + host_action_prompt_begin(PROMPT_FILAMENT_RUNOUT, PSTR("FilamentRunout T"), tool); + host_action_prompt_show(); + #endif + + const bool run_runout_script = !runout.host_handling; + + #if ENABLED(HOST_ACTION_COMMANDS) + if (run_runout_script + && (strstr(FILAMENT_RUNOUT_SCRIPT, "M600") + || strstr(FILAMENT_RUNOUT_SCRIPT, "M125") + || TERN0(ADVANCED_PAUSE_FEATURE, strstr(FILAMENT_RUNOUT_SCRIPT, "M25"))) + ) { + host_action_paused(false); + } + else { + #ifdef ACTION_ON_FILAMENT_RUNOUT + host_action(PSTR(ACTION_ON_FILAMENT_RUNOUT " T"), false); + SERIAL_CHAR(tool); + SERIAL_EOL(); + #endif + host_action_pause(false); + } + SERIAL_ECHOPGM(" " ACTION_REASON_ON_FILAMENT_RUNOUT " "); + SERIAL_CHAR(tool); + SERIAL_EOL(); + #endif // HOST_ACTION_COMMANDS + + if (run_runout_script) { + #if MULTI_FILAMENT_SENSOR + char script[strlen(FILAMENT_RUNOUT_SCRIPT) + 1]; + sprintf_P(script, PSTR(FILAMENT_RUNOUT_SCRIPT), tool); + #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) + SERIAL_ECHOLNPAIR("Runout Command: ", script); + #endif + queue.inject(script); + #else + #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) + SERIAL_ECHOPGM("Runout Command: "); + SERIAL_ECHOLNPGM(FILAMENT_RUNOUT_SCRIPT); + #endif + queue.inject_P(PSTR(FILAMENT_RUNOUT_SCRIPT)); + #endif + } + } + + #endif // HAS_FILAMENT_SENSOR \ No newline at end of file diff --git a/Marlin/src/feature/runout.h b/Marlin/src/feature/runout.h index 93eb59c2a5..14b59ce7e7 100644 --- a/Marlin/src/feature/runout.h +++ b/Marlin/src/feature/runout.h @@ -21,6 +21,9 @@ */ #pragma once +#ifndef RUNOUT_H +#define RUNOUT_H + /** * feature/runout.h - Runout sensor support */ @@ -31,38 +34,19 @@ #include "../module/stepper.h" // for block_t #include "../gcode/queue.h" #include "../feature/pause.h" - #include "../inc/MarlinConfig.h" #if ENABLED(EXTENSIBLE_UI) #include "../lcd/extui/ui_api.h" #endif +#if HAS_FILAMENT_SENSOR + //#define FILAMENT_RUNOUT_SENSOR_DEBUG #ifndef FILAMENT_RUNOUT_THRESHOLD #define FILAMENT_RUNOUT_THRESHOLD 5 #endif -void event_filament_runout(const uint8_t extruder); - -template -class TFilamentMonitor; -class FilamentSensorEncoder; -class FilamentSensorSwitch; -class RunoutResponseDelayed; -class RunoutResponseDebounced; - -/********************************* TEMPLATE SPECIALIZATION *********************************/ - -typedef TFilamentMonitor< - TERN(HAS_FILAMENT_RUNOUT_DISTANCE, RunoutResponseDelayed, RunoutResponseDebounced), - TERN(FILAMENT_MOTION_SENSOR, FilamentSensorEncoder, FilamentSensorSwitch) - > FilamentMonitor; - -extern FilamentMonitor runout; - -/*******************************************************************************************/ - class FilamentMonitorBase { public: static bool enabled, filament_ran_out; @@ -74,340 +58,23 @@ class FilamentMonitorBase { #endif }; -template -class TFilamentMonitor : public FilamentMonitorBase { - private: - typedef RESPONSE_T response_t; - typedef SENSOR_T sensor_t; - static response_t response; - static sensor_t sensor; - +class FilamentMonitor : public FilamentMonitorBase { public: - static inline void setup() { - sensor.setup(); - reset(); - } - - static inline void reset() { - filament_ran_out = false; - response.reset(); - } - - // Call this method when filament is present, - // so the response can reset its counter. - static inline void filament_present(const uint8_t extruder) { - response.filament_present(extruder); - } + static void setup(); + static void reset(); + static void filament_present(const uint8_t extruder); + static void runout_detected(const uint8_t extruder); // Fixed: Added extruder parameter + static bool is_triggered(const uint8_t extruder) { return triggered[extruder]; } + static void set_triggered(const uint8_t extruder, bool value) { triggered[extruder] = value; } - #if HAS_FILAMENT_RUNOUT_DISTANCE - static inline float& runout_distance() { return response.runout_distance_mm; } - static inline void set_runout_distance(const_float_t mm) { response.runout_distance_mm = mm; } - #endif - - // Handle a block completion. RunoutResponseDelayed uses this to - // add up the length of filament moved while the filament is out. - static inline void block_completed(const block_t * const b) { - if (enabled) { - response.block_completed(b); - sensor.block_completed(b); - } - } - - // Give the response a chance to update its counter. - static inline void run() { - if (enabled && !filament_ran_out && (printingIsActive() || did_pause_print)) { - TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, cli()); // Prevent RunoutResponseDelayed::block_completed from accumulating here - response.run(); - sensor.run(); - const uint8_t runout_flags = response.has_run_out(); - TERN_(HAS_FILAMENT_RUNOUT_DISTANCE, sei()); - #if MULTI_FILAMENT_SENSOR - #if ENABLED(WATCH_ALL_RUNOUT_SENSORS) - const bool ran_out = !!runout_flags; // any sensor triggers - uint8_t extruder = 0; - if (ran_out) { - uint8_t bitmask = runout_flags; - while (!(bitmask & 1)) { - bitmask >>= 1; - extruder++; - } - } - #else - const bool ran_out = TEST(runout_flags, active_extruder); // suppress non active extruders - uint8_t extruder = active_extruder; - #endif - #else - const bool ran_out = !!runout_flags; - uint8_t extruder = active_extruder; - #endif - - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - if (runout_flags) { - SERIAL_ECHOPGM("Runout Sensors: "); - LOOP_L_N(i, 8) SERIAL_ECHO('0' + TEST(runout_flags, i)); - SERIAL_ECHOPAIR(" -> ", extruder); - if (ran_out) SERIAL_ECHOPGM(" RUN OUT"); - SERIAL_EOL(); - } - #endif - - if (ran_out) { - filament_ran_out = true; - event_filament_runout(extruder); - planner.synchronize(); - } - } - } -}; - -/*************************** FILAMENT PRESENCE SENSORS ***************************/ - -class FilamentSensorBase { - protected: - /** - * Called by FilamentSensorSwitch::run when filament is detected. - * Called by FilamentSensorEncoder::block_completed when motion is detected. - */ - static inline void filament_present(const uint8_t extruder) { - runout.filament_present(extruder); // ...which calls response.filament_present(extruder) - } - - public: - static inline void setup() { - #define _INIT_RUNOUT_PIN(P,S,U,D) do{ if (ENABLED(U)) SET_INPUT_PULLUP(P); else if (ENABLED(D)) SET_INPUT_PULLDOWN(P); else SET_INPUT(P); }while(0) - #define INIT_RUNOUT_PIN(N) _INIT_RUNOUT_PIN(FIL_RUNOUT##N##_PIN, FIL_RUNOUT##N##_STATE, FIL_RUNOUT##N##_PULLUP, FIL_RUNOUT##N##_PULLDOWN) - #if NUM_RUNOUT_SENSORS >= 1 - INIT_RUNOUT_PIN(1); - #endif - #if NUM_RUNOUT_SENSORS >= 2 - INIT_RUNOUT_PIN(2); - #endif - #if NUM_RUNOUT_SENSORS >= 3 - INIT_RUNOUT_PIN(3); - #endif - #if NUM_RUNOUT_SENSORS >= 4 - INIT_RUNOUT_PIN(4); - #endif - #if NUM_RUNOUT_SENSORS >= 5 - INIT_RUNOUT_PIN(5); - #endif - #if NUM_RUNOUT_SENSORS >= 6 - INIT_RUNOUT_PIN(6); - #endif - #if NUM_RUNOUT_SENSORS >= 7 - INIT_RUNOUT_PIN(7); - #endif - #if NUM_RUNOUT_SENSORS >= 8 - INIT_RUNOUT_PIN(8); - #endif - #undef _INIT_RUNOUT_PIN - #undef INIT_RUNOUT_PIN - } - - // Return a bitmask of runout pin states - static inline uint8_t poll_runout_pins() { - #define _OR_RUNOUT(N) | (READ(FIL_RUNOUT##N##_PIN) ? _BV((N) - 1) : 0) - return (0 REPEAT_1(NUM_RUNOUT_SENSORS, _OR_RUNOUT)); - #undef _OR_RUNOUT - } - - // Return a bitmask of runout flag states (1 bits always indicates runout) - static inline uint8_t poll_runout_states() { - return poll_runout_pins() ^ uint8_t(0 - #if NUM_RUNOUT_SENSORS >= 1 - | (FIL_RUNOUT1_STATE ? 0 : _BV(1 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 2 - | (FIL_RUNOUT2_STATE ? 0 : _BV(2 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 3 - | (FIL_RUNOUT3_STATE ? 0 : _BV(3 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 4 - | (FIL_RUNOUT4_STATE ? 0 : _BV(4 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 5 - | (FIL_RUNOUT5_STATE ? 0 : _BV(5 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 6 - | (FIL_RUNOUT6_STATE ? 0 : _BV(6 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 7 - | (FIL_RUNOUT7_STATE ? 0 : _BV(7 - 1)) - #endif - #if NUM_RUNOUT_SENSORS >= 8 - | (FIL_RUNOUT8_STATE ? 0 : _BV(8 - 1)) - #endif - ); - } + private: + static bool triggered[NUM_RUNOUT_SENSORS]; // Track runout state per extruder }; -#if ENABLED(FILAMENT_MOTION_SENSOR) - - /** - * This sensor uses a magnetic encoder disc and a Hall effect - * sensor (or a slotted disc and optical sensor). The state - * will toggle between 0 and 1 on filament movement. It can detect - * filament runout and stripouts or jams. - */ - class FilamentSensorEncoder : public FilamentSensorBase { - private: - static uint8_t motion_detected; - - static inline void poll_motion_sensor() { - static uint8_t old_state; - const uint8_t new_state = poll_runout_pins(), - change = old_state ^ new_state; - old_state = new_state; - - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - if (change) { - SERIAL_ECHOPGM("Motion detected:"); - LOOP_L_N(e, NUM_RUNOUT_SENSORS) - if (TEST(change, e)) SERIAL_CHAR(' ', '0' + e); - SERIAL_EOL(); - } - #endif - - motion_detected |= change; - } - - public: - static inline void block_completed(const block_t * const b) { - // If the sensor wheel has moved since the last call to - // this method reset the runout counter for the extruder. - if (TEST(motion_detected, b->extruder)) - filament_present(b->extruder); - - // Clear motion triggers for next block - motion_detected = 0; - } - - static inline void run() { poll_motion_sensor(); } - }; - -#else - - /** - * This is a simple endstop switch in the path of the filament. - * It can detect filament runout, but not stripouts or jams. - */ - class FilamentSensorSwitch : public FilamentSensorBase { - private: - static inline bool poll_runout_state(const uint8_t extruder) { - const uint8_t runout_states = poll_runout_states(); - #if MULTI_FILAMENT_SENSOR - if ( !TERN0(DUAL_X_CARRIAGE, idex_is_duplicating()) - && !TERN0(MULTI_NOZZLE_DUPLICATION, extruder_duplication_enabled) - ) return TEST(runout_states, extruder); // A specific extruder ran out - #else - UNUSED(extruder); - #endif - return !!runout_states; // Any extruder ran out - } - - public: - static inline void block_completed(const block_t * const) {} - - static inline void run() { - LOOP_L_N(s, NUM_RUNOUT_SENSORS) { - const bool out = poll_runout_state(s); - if (!out) filament_present(s); - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - static uint8_t was_out; // = 0 - if (out != TEST(was_out, s)) { - TBI(was_out, s); - SERIAL_ECHOLNPAIR_P(PSTR("Filament Sensor "), '0' + s, out ? PSTR(" OUT") : PSTR(" IN")); - } - #endif - } - } - }; - - -#endif // !FILAMENT_MOTION_SENSOR - -/********************************* RESPONSE TYPE *********************************/ - -#if HAS_FILAMENT_RUNOUT_DISTANCE - - // RunoutResponseDelayed triggers a runout event only if the length - // of filament specified by FILAMENT_RUNOUT_DISTANCE_MM has been fed - // during a runout condition. - class RunoutResponseDelayed { - private: - static volatile float runout_mm_countdown[NUM_RUNOUT_SENSORS]; - - public: - static float runout_distance_mm; - - static inline void reset() { - LOOP_L_N(i, NUM_RUNOUT_SENSORS) filament_present(i); - } - - static inline void run() { - #if ENABLED(FILAMENT_RUNOUT_SENSOR_DEBUG) - static millis_t t = 0; - const millis_t ms = millis(); - if (ELAPSED(ms, t)) { - t = millis() + 1000UL; - LOOP_L_N(i, NUM_RUNOUT_SENSORS) - SERIAL_ECHOPAIR_P(i ? PSTR(", ") : PSTR("Remaining mm: "), runout_mm_countdown[i]); - SERIAL_EOL(); - } - #endif - } - - static inline uint8_t has_run_out() { - uint8_t runout_flags = 0; - LOOP_L_N(i, NUM_RUNOUT_SENSORS) if (runout_mm_countdown[i] < 0) SBI(runout_flags, i); - return runout_flags; - } - - static inline void filament_present(const uint8_t extruder) { - runout_mm_countdown[extruder] = runout_distance_mm; - } - - static inline void block_completed(const block_t * const b) { - if (b->steps.x || b->steps.y || b->steps.z || did_pause_print) { // Allow pause purge move to re-trigger runout state - // Only trigger on extrusion with XYZ movement to allow filament change and retract/recover. - const uint8_t e = b->extruder; - const int32_t steps = b->steps.e; - runout_mm_countdown[e] -= (TEST(b->direction_bits, E_AXIS) ? -steps : steps) * planner.steps_to_mm[E_AXIS_N(e)]; - } - } - }; - -#else // !HAS_FILAMENT_RUNOUT_DISTANCE - - // RunoutResponseDebounced triggers a runout event after a runout - // condition has been detected runout_threshold times in a row. - - class RunoutResponseDebounced { - private: - static constexpr int8_t runout_threshold = FILAMENT_RUNOUT_THRESHOLD; - static int8_t runout_count[NUM_RUNOUT_SENSORS]; - - public: - static inline void reset() { - LOOP_L_N(i, NUM_RUNOUT_SENSORS) filament_present(i); - } - - static inline void run() { - LOOP_L_N(i, NUM_RUNOUT_SENSORS) if (runout_count[i] >= 0) runout_count[i]--; - } - - static inline uint8_t has_run_out() { - uint8_t runout_flags = 0; - LOOP_L_N(i, NUM_RUNOUT_SENSORS) if (runout_count[i] < 0) SBI(runout_flags, i); - return runout_flags; - } +extern FilamentMonitor runout; - static inline void block_completed(const block_t * const) { } +void event_filament_runout(const uint8_t extruder); - static inline void filament_present(const uint8_t extruder) { - runout_count[extruder] = runout_threshold; - } - }; +#endif // HAS_FILAMENT_SENSOR -#endif // !HAS_FILAMENT_RUNOUT_DISTANCE +#endif // RUNOUT_H \ No newline at end of file diff --git a/Marlin/src/gcode/feature/pause/G27.cpp b/Marlin/src/gcode/feature/pause/G27.cpp index 3ce618d675..8729392a1c 100644 --- a/Marlin/src/gcode/feature/pause/G27.cpp +++ b/Marlin/src/gcode/feature/pause/G27.cpp @@ -21,21 +21,36 @@ */ -#include "../../../inc/MarlinConfig.h" + #include "../../../inc/MarlinConfig.h" #if ENABLED(NOZZLE_PARK_FEATURE) #include "../../gcode.h" #include "../../../libs/nozzle.h" #include "../../../module/motion.h" - +#include "../../module/endstops.h" /** * G27: Park the nozzle */ void GcodeSuite::G27() { // Don't allow nozzle parking without homing first if (homing_needed_error()) return; - nozzle.park(parser.ushortval('P')); + + // Define park_point based on active extruder with direct initialization + xyz_pos_t park_point; + if (active_extruder == 0) { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T0}; + } else { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T1}; + } + + #if ENABLED(DUAL_X_CARRIAGE) + if (active_extruder == 1) endstops.enable_globally(false); // Allow T1 to reach X=331 + #endif + nozzle.park(parser.ushortval('P'), park_point); + #if ENABLED(DUAL_X_CARRIAGE) + if (active_extruder == 1) endstops.enable_globally(true); // Restore endstops + #endif } -#endif // NOZZLE_PARK_FEATURE +#endif // NOZZLE_PARK_FEATURE \ No newline at end of file diff --git a/Marlin/src/gcode/feature/pause/M125.cpp b/Marlin/src/gcode/feature/pause/M125.cpp index bc31e1225d..7e252b6abc 100644 --- a/Marlin/src/gcode/feature/pause/M125.cpp +++ b/Marlin/src/gcode/feature/pause/M125.cpp @@ -20,7 +20,7 @@ * */ -#include "../../../inc/MarlinConfig.h" + #include "../../../inc/MarlinConfig.h" #if ENABLED(PARK_HEAD_ON_PAUSE) @@ -31,40 +31,22 @@ #include "../../../module/motion.h" #include "../../../module/printcounter.h" #include "../../../sd/cardreader.h" - +#include "../../module/endstops.h" #if ENABLED(POWER_LOSS_RECOVERY) #include "../../../feature/powerloss.h" #endif -/** - * M125: Store current position and move to parking position. - * Called on pause (by M25) to prevent material leaking onto the - * object. On resume (M24) the head will be moved back and the - * print will resume. - * - * When not actively SD printing, M125 simply moves to the park - * position and waits, resuming with a button click or M108. - * Without PARK_HEAD_ON_PAUSE the M125 command does nothing. - * - * L = Override retract Length - * X = Override park position X - * Y = Override park position Y - * Z = Override Z raise - * - * With an LCD menu: - * P = Always show a prompt and await a response - */ void GcodeSuite::M125() { - // Initial retract before move to filament change position const float retract = TERN0(HAS_EXTRUDERS, -ABS(parser.axisunitsval('L', E_AXIS, PAUSE_PARK_RETRACT_LENGTH))); + xyz_pos_t park_point; + if (active_extruder == 0) { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T0}; + } else { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T1}; + } - xyz_pos_t park_point = NOZZLE_PARK_POINT; - - // Move XY axes to filament change position or given position if (parser.seenval('X')) park_point.x = RAW_X_POSITION(parser.linearval('X')); if (parser.seenval('Y')) park_point.y = RAW_X_POSITION(parser.linearval('Y')); - - // Lift Z axis if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) @@ -72,18 +54,21 @@ void GcodeSuite::M125() { #endif const bool sd_printing = TERN0(SDSUPPORT, IS_SD_PRINTING()); - ui.pause_show_message(PAUSE_MESSAGE_PARKING, PAUSE_MODE_PAUSE_PRINT); - - // If possible, show an LCD prompt with the 'P' flag const bool show_lcd = TERN0(HAS_LCD_MENU, parser.boolval('P')); + #if ENABLED(DUAL_X_CARRIAGE) + if (active_extruder == 1) endstops.enable_globally(false); + #endif if (pause_print(retract, park_point, show_lcd, 0)) { if (ENABLED(EXTENSIBLE_UI) || BOTH(EMERGENCY_PARSER, HOST_PROMPT_SUPPORT) || !sd_printing || show_lcd) { wait_for_confirmation(false, 0); resume_print(0, 0, -retract, 0); } } + #if ENABLED(DUAL_X_CARRIAGE) + if (active_extruder == 1) endstops.enable_globally(true); + #endif } -#endif // PARK_HEAD_ON_PAUSE +#endif // PARK_HEAD_ON_PAUSE \ No newline at end of file diff --git a/Marlin/src/gcode/feature/pause/M600.cpp b/Marlin/src/gcode/feature/pause/M600.cpp index 1631938aa7..e1468e0b65 100644 --- a/Marlin/src/gcode/feature/pause/M600.cpp +++ b/Marlin/src/gcode/feature/pause/M600.cpp @@ -19,169 +19,95 @@ * along with this program. If not, see . * */ - #include "../../../inc/MarlinConfig.h" - +#include "../../../module/temperature.h" #include "../../gcode.h" #include "../../../feature/pause.h" #include "../../../module/motion.h" #include "../../../module/planner.h" #include "../../../module/printcounter.h" #include "../../../lcd/marlinui.h" +#include "../../../module/tool_change.h" +#include "../../../feature/runout.h" #include "../../../../../snapmaker/debug/debug.h" #include "../../../../../snapmaker/module/print_control.h" #include "../../../../../snapmaker/module/power_loss.h" +#include "../../../../../snapmaker/module/filament_sensor.h" #include "../../../../../snapmaker/module/system.h" - +#include "../../module/endstops.h" void GcodeSuite::M600() { - planner.synchronize(); - power_loss.m600_cur_line = queue.file_line_number(); - LOG_I("power_loss.m600_cur_line set to %d\r\n", power_loss.cur_line); - system_service.set_status(SYSTEM_STATUE_PAUSING, SYSTEM_STATUE_SCOURCE_M600); -} - -#if ENABLED(ADVANCED_PAUSE_FEATURE) - -#include "../../gcode.h" -#include "../../../feature/pause.h" -#include "../../../module/motion.h" -#include "../../../module/printcounter.h" -#include "../../../lcd/marlinui.h" - -#if HAS_MULTI_EXTRUDER - #include "../../../module/tool_change.h" -#endif - -#if ENABLED(MMU2_MENUS) - #include "../../../lcd/menu/menu_mmu2.h" -#endif - -#if ENABLED(MIXING_EXTRUDER) - #include "../../../feature/mixing.h" -#endif - -#if HAS_FILAMENT_SENSOR - #include "../../../feature/runout.h" -#endif - -/** - * M600: Pause for filament change - * - * E[distance] - Retract the filament this far - * Z[distance] - Move the Z axis by this distance - * X[position] - Move to this X position, with Y - * Y[position] - Move to this Y position, with X - * U[distance] - Retract distance for removal (manual reload) - * L[distance] - Extrude distance for insertion (manual reload) - * B[count] - Number of times to beep, -1 for indefinite (if equipped with a buzzer) - * T[toolhead] - Select extruder for filament change - * R[temp] - Resume temperature (in current units) - * - * Default values are used for omitted arguments. - */ -void GcodeSuite::M600() { - - #if ENABLED(MIXING_EXTRUDER) - const int8_t target_e_stepper = get_target_e_stepper_from_command(); - if (target_e_stepper < 0) return; - - const uint8_t old_mixing_tool = mixer.get_current_vtool(); - mixer.T(MIXER_DIRECT_SET_TOOL); - - MIXER_STEPPER_LOOP(i) mixer.set_collector(i, i == uint8_t(target_e_stepper) ? 1.0 : 0.0); - mixer.normalize(); + if (is_hmi_printing) { + planner.synchronize(); + power_loss.m600_cur_line = queue.file_line_number(); + LOG_I("power_loss.m600_cur_line set to %d\r\n", power_loss.cur_line); + system_service.set_status(SYSTEM_STATUE_PAUSING, SYSTEM_STATUE_SCOURCE_M600); + } - const int8_t target_extruder = active_extruder; - #else + #if ENABLED(ADVANCED_PAUSE_FEATURE) && !IS_HMI_PRINTING const int8_t target_extruder = get_target_extruder_from_command(); if (target_extruder < 0) return; - #endif - - #if ENABLED(DUAL_X_CARRIAGE) - int8_t DXC_ext = target_extruder; - if (!parser.seen_test('T')) { // If no tool index is specified, M600 was (probably) sent in response to filament runout. - // In this case, for duplicating modes set DXC_ext to the extruder that ran out. - #if MULTI_FILAMENT_SENSOR - if (idex_is_duplicating()) - DXC_ext = (READ(FIL_RUNOUT2_PIN) == FIL_RUNOUT2_STATE) ? 1 : 0; - #else - DXC_ext = active_extruder; - #endif - } - #endif - - // Show initial "wait for start" message - #if DISABLED(MMU2_MENUS) - ui.pause_show_message(PAUSE_MESSAGE_CHANGING, PAUSE_MODE_PAUSE_PRINT, target_extruder); - #endif - #if ENABLED(HOME_BEFORE_FILAMENT_CHANGE) - // If needed, home before parking for filament change - home_if_needed(true); - #endif - - #if HAS_MULTI_EXTRUDER - // Change toolhead if specified - const uint8_t active_extruder_before_filament_change = active_extruder; - if (active_extruder != target_extruder && TERN1(DUAL_X_CARRIAGE, !idex_is_duplicating())) - tool_change(target_extruder, false); - #endif - - // Initial retract before move to filament change position - const float retract = -ABS(parser.axisunitsval('E', E_AXIS, PAUSE_PARK_RETRACT_LENGTH)); - - xyz_pos_t park_point NOZZLE_PARK_POINT; - - // Lift Z axis - if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + #if ENABLED(DUAL_X_CARRIAGE) + int8_t DXC_ext = target_extruder; + if (!parser.seen_test('T')) { + DXC_ext = filament_sensor.is_trigger(1) ? 1 : 0; + } + #else + #define DXC_ext target_extruder + #endif - // Move XY axes to filament change position or given position - if (parser.seenval('X')) park_point.x = parser.linearval('X'); - if (parser.seenval('Y')) park_point.y = parser.linearval('Y'); + #if HAS_MULTI_EXTRUDER + const uint8_t active_extruder_before_filament_change = active_extruder; + if (active_extruder != target_extruder && TERN1(DUAL_X_CARRIAGE, !idex_is_duplicating())) + tool_change(target_extruder, false); + #endif - #if HAS_HOTEND_OFFSET && NONE(DUAL_X_CARRIAGE, DELTA) - park_point += hotend_offset[active_extruder]; - #endif + const float retract = -ABS(parser.axisunitsval('E', E_AXIS, PAUSE_PARK_RETRACT_LENGTH)); + // Select park point based on target extruder using separate macros + xyz_pos_t park_point; + if (target_extruder == 0) { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T0}; + } else { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T1}; + } + // Override with command parameters if provided + if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); + if (parser.seenval('X')) park_point.x = parser.linearval('X'); + if (parser.seenval('Y')) park_point.y = parser.linearval('Y'); - #if ENABLED(MMU2_MENUS) - // For MMU2 reset retract and load/unload values so they don't mess with MMU filament handling - constexpr float unload_length = 0.5f, - slow_load_length = 0.0f, - fast_load_length = 0.0f; - #else - // Unload filament const float unload_length = -ABS(parser.axisunitsval('U', E_AXIS, fc_settings[active_extruder].unload_length)); - // Slow load filament constexpr float slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH; - // Fast load filament const float fast_load_length = ABS(parser.axisunitsval('L', E_AXIS, fc_settings[active_extruder].load_length)); - #endif + const int8_t beep_count = parser.intval('B', -1); - const int beep_count = parser.intval('B', -1 - #ifdef FILAMENT_CHANGE_ALERT_BEEPS - + 1 + FILAMENT_CHANGE_ALERT_BEEPS + SERIAL_ECHOLNPAIR("M600: Pausing print for extruder ", target_extruder); + SERIAL_ECHOLNPAIR("M600: Parking at X=", park_point.x, " Y=", park_point.y, " Z=", park_point.z); + is_m600_pause = true; + + #if ENABLED(DUAL_X_CARRIAGE) + if (target_extruder == 1) endstops.enable_globally(false); #endif - ); + if (pause_print(retract, park_point, true, unload_length DXC_PASS)) { + SERIAL_ECHOLNPGM("M600: Pause succeeded"); + wait_for_confirmation(false, beep_count DXC_PASS); - if (pause_print(retract, park_point, true, unload_length DXC_PASS)) { - #if ENABLED(MMU2_MENUS) - mmu2_M600(); - resume_print(slow_load_length, fast_load_length, 0, beep_count DXC_PASS); - #else - wait_for_confirmation(true, beep_count DXC_PASS); + SERIAL_ECHOLNPGM("M600: Resuming print"); resume_print(slow_load_length, fast_load_length, ADVANCED_PAUSE_PURGE_LENGTH, beep_count, (parser.seenval('R') ? parser.value_celsius() : 0) DXC_PASS); + } + else { + SERIAL_ECHOLNPGM("M600: Pause failed"); + } + #if ENABLED(DUAL_X_CARRIAGE) + if (target_extruder == 1) endstops.enable_globally(true); #endif - } - #if HAS_MULTI_EXTRUDER - // Restore toolhead if it was changed - if (active_extruder_before_filament_change != active_extruder) - tool_change(active_extruder_before_filament_change, false); - #endif + is_m600_pause = false; - TERN_(MIXING_EXTRUDER, mixer.T(old_mixing_tool)); // Restore original mixing tool -} - -#endif // ADVANCED_PAUSE_FEATURE + #if HAS_MULTI_EXTRUDER + if (active_extruder_before_filament_change != active_extruder) + tool_change(active_extruder_before_filament_change, false); + #endif + #endif // ADVANCED_PAUSE_FEATURE && !IS_HMI_PRINTING +} \ No newline at end of file diff --git a/Marlin/src/gcode/feature/pause/M701_M702.cpp b/Marlin/src/gcode/feature/pause/M701_M702.cpp index 0a649dadd4..3fac7c8621 100644 --- a/Marlin/src/gcode/feature/pause/M701_M702.cpp +++ b/Marlin/src/gcode/feature/pause/M701_M702.cpp @@ -20,13 +20,14 @@ * */ -#include "../../../inc/MarlinConfigPre.h" + #include "../../../inc/MarlinConfigPre.h" #if ENABLED(FILAMENT_LOAD_UNLOAD_GCODES) #include "../../gcode.h" #include "../../../MarlinCore.h" #include "../../../module/motion.h" +#include "../../module/endstops.h" // Added for DUAL_X_CARRIAGE endstop handling #include "../../../module/temperature.h" #include "../../../feature/pause.h" #include "../../../lcd/marlinui.h" @@ -54,38 +55,43 @@ * Default values are used for omitted arguments. */ void GcodeSuite::M701() { - xyz_pos_t park_point = NOZZLE_PARK_POINT; + // Define park_point based on target extruder + xyz_pos_t park_point; + const int8_t target_extruder = get_target_extruder_from_command(); + if (target_extruder < 0) return; // Early return if no valid extruder + if (target_extruder == 0) { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T0}; + } else { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T1}; + } // Don't raise Z if the machine isn't homed if (TERN0(NO_MOTION_BEFORE_HOMING, axes_should_home())) park_point.z = 0; #if ENABLED(MIXING_EXTRUDER) - const int8_t target_e_stepper = get_target_e_stepper_from_command(); - if (target_e_stepper < 0) return; - + const int8_t target_e_stepper = target_extruder; // Use target_extruder directly const uint8_t old_mixing_tool = mixer.get_current_vtool(); mixer.T(MIXER_DIRECT_SET_TOOL); MIXER_STEPPER_LOOP(i) mixer.set_collector(i, (i == (uint8_t)target_e_stepper) ? 1.0 : 0.0); mixer.normalize(); - const int8_t target_extruder = active_extruder; + const int8_t target_extruder_local = active_extruder; // Rename to avoid shadowing #else - const int8_t target_extruder = get_target_extruder_from_command(); - if (target_extruder < 0) return; + const int8_t target_extruder_local = target_extruder; // Already set above #endif // Z axis lift if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); // Show initial "wait for load" message - ui.pause_show_message(PAUSE_MESSAGE_LOAD, PAUSE_MODE_LOAD_FILAMENT, target_extruder); + ui.pause_show_message(PAUSE_MESSAGE_LOAD, PAUSE_MODE_LOAD_FILAMENT, target_extruder_local); #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU) // Change toolhead if specified uint8_t active_extruder_before_filament_change = active_extruder; - if (active_extruder != target_extruder) - tool_change(target_extruder, false); + if (active_extruder != target_extruder_local) + tool_change(target_extruder_local, false); #endif auto move_z_by = [](const_float_t zdist) { @@ -102,20 +108,20 @@ void GcodeSuite::M701() { // Load filament #if HAS_PRUSA_MMU2 - mmu2.load_filament_to_nozzle(target_extruder); + mmu2.load_filament_to_nozzle(target_extruder_local); #else constexpr float purge_length = ADVANCED_PAUSE_PURGE_LENGTH, - slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH; - const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) - : fc_settings[active_extruder].load_length); + slow_load_length = FILAMENT_CHANGE_SLOW_LOAD_LENGTH; + const float fast_load_length = ABS(parser.seen('L') ? parser.value_axis_units(E_AXIS) + : fc_settings[active_extruder].load_length); load_filament( slow_load_length, fast_load_length, purge_length, FILAMENT_CHANGE_ALERT_BEEPS, true, // show_lcd - thermalManager.still_heating(target_extruder), // pause_for_user + thermalManager.still_heating(target_extruder_local), // pause_for_user PAUSE_MODE_LOAD_FILAMENT // pause_mode #if ENABLED(DUAL_X_CARRIAGE) - , target_extruder // Dual X target + , target_extruder_local // Dual X target #endif ); #endif @@ -147,7 +153,15 @@ void GcodeSuite::M701() { * Default values are used for omitted arguments. */ void GcodeSuite::M702() { - xyz_pos_t park_point = NOZZLE_PARK_POINT; + // Define park_point based on target extruder + xyz_pos_t park_point; + const int8_t target_extruder = get_target_extruder_from_command(); + if (target_extruder < 0) return; // Early return if no valid extruder + if (target_extruder == 0) { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T0}; + } else { + park_point = xyz_pos_t{NOZZLE_PARK_POINT_T1}; + } // Don't raise Z if the machine isn't homed if (TERN0(NO_MOTION_BEFORE_HOMING, axes_should_home())) park_point.z = 0; @@ -167,30 +181,28 @@ void GcodeSuite::M702() { #endif if (seenT) { - const int8_t target_e_stepper = get_target_e_stepper_from_command(); - if (target_e_stepper < 0) return; + const int8_t target_e_stepper = target_extruder; // Use target_extruder directly mixer.T(MIXER_DIRECT_SET_TOOL); MIXER_STEPPER_LOOP(i) mixer.set_collector(i, (i == (uint8_t)target_e_stepper) ? 1.0 : 0.0); mixer.normalize(); } - const int8_t target_extruder = active_extruder; + const int8_t target_extruder_local = active_extruder; // Rename to avoid shadowing #else - const int8_t target_extruder = get_target_extruder_from_command(); - if (target_extruder < 0) return; + const int8_t target_extruder_local = target_extruder; // Already set above #endif // Z axis lift if (parser.seenval('Z')) park_point.z = parser.linearval('Z'); // Show initial "wait for unload" message - ui.pause_show_message(PAUSE_MESSAGE_UNLOAD, PAUSE_MODE_UNLOAD_FILAMENT, target_extruder); + ui.pause_show_message(PAUSE_MESSAGE_UNLOAD, PAUSE_MODE_UNLOAD_FILAMENT, target_extruder_local); #if HAS_MULTI_EXTRUDER && (HAS_PRUSA_MMU1 || !HAS_MMU) // Change toolhead if specified uint8_t active_extruder_before_filament_change = active_extruder; - if (active_extruder != target_extruder) - tool_change(target_extruder, false); + if (active_extruder != target_extruder_local) + tool_change(target_extruder_local, false); #endif // Lift Z axis @@ -213,7 +225,7 @@ void GcodeSuite::M702() { { // Unload length const float unload_length = -ABS(parser.seen('U') ? parser.value_axis_units(E_AXIS) - : fc_settings[target_extruder].unload_length); + : fc_settings[target_extruder_local].unload_length); unload_filament(unload_length, true, PAUSE_MODE_UNLOAD_FILAMENT #if ALL(FILAMENT_UNLOAD_ALL_EXTRUDERS, MIXING_EXTRUDER) @@ -239,4 +251,4 @@ void GcodeSuite::M702() { ui.pause_show_message(PAUSE_MESSAGE_STATUS); } -#endif // ADVANCED_PAUSE_FEATURE +#endif // ADVANCED_PAUSE_FEATURE \ No newline at end of file diff --git a/Marlin/src/gcode/feature/runout/M412.cpp b/Marlin/src/gcode/feature/runout/M412.cpp index 62cf9dc3ec..d6568769b8 100644 --- a/Marlin/src/gcode/feature/runout/M412.cpp +++ b/Marlin/src/gcode/feature/runout/M412.cpp @@ -20,83 +20,53 @@ * */ -#include "../../../inc/MarlinConfig.h" + #include "../../../inc/MarlinConfig.h" -// #if HAS_FILAMENT_SENSOR - -#include "../../gcode.h" -// #include "../../../feature/runout.h" -#include "../../../../../snapmaker/module/filament_sensor.h" -#include "../../../module/settings.h" - -/** - * M412: Enable / Disable filament runout detection - * - * Parameters - * R : Reset the runout sensor - * S : Reset and enable/disable the runout sensor - * H : Enable/disable host handling of filament runout - * D : Extra distance to continue after runout is triggered - */ -void GcodeSuite::M412() { - - bool need_save = false; - - if (parser.seenval('S')) { - bool enable = parser.value_bool(); - uint8_t e = 0; - if (parser.seenval('T')) { - e = parser.value_bool(); - } - filament_sensor.filament_param.enabled[e] = enable; - need_save = true; - } - - if (parser.seenval('D')) { - uint8_t d = parser.value_byte(); - if (d < 1) { - d = 1; - } - filament_sensor.filament_param.distance = d; - need_save = true; - } - - // if (parser.seenval('H')) { - // uint16_t h = parser.value_ushort(); - // if (h < 1) { - // h = 1; - // } - // filament_sensor.filament_param.threshold = h; - // need_save = true; - // } - - // if (parser.seenval('N')) { - // uint8_t n = parser.value_byte(); - // if (n < 1) { - // n = 1; - // } else if (n > 8){ - // n = 8; - // } - // filament_sensor.filament_param.check_times = n; - // need_save = true; - // } - - if (parser.seen('R') || need_save) { - if (need_save) - (void)settings.save(); - filament_sensor.reset(); - } - - SERIAL_ECHOLNPAIR("filament check enable T[0]:", filament_sensor.filament_param.enabled[0], - ", T[1]:", filament_sensor.filament_param.enabled[1]); - - // SERIAL_ECHOLNPAIR("filament check param - diatance:", filament_sensor.filament_param.distance, - // ", threshold:", filament_sensor.filament_param.threshold, - // ", times:", filament_sensor.filament_param.check_times); - SERIAL_ECHOLNPAIR("filament check param - diatance:", filament_sensor.filament_param.distance); - - SERIAL_ECHOLNPAIR("filament sensor value T[0]:", filament_sensor.get_adc_val(0), - ", T[1]:", filament_sensor.get_adc_val(1)); -} - -// #endif // HAS_FILAMENT_SENSOR + #include "../../gcode.h" + #include "../../snapmaker/module/filament_sensor.h" + #include "../../../module/settings.h" + + /** + * M412: Enable / Disable filament runout detection + * + * Parameters + * R : Reset the runout sensor + * S : Reset and enable/disable the runout sensor + * H : Enable/disable host handling of filament runout + * D : Extra distance to continue after runout is triggered + */ + void GcodeSuite::M412() { + + bool need_save = false; + + if (parser.seenval('S')) { + bool enable = parser.value_bool(); + uint8_t e = 0; + if (parser.seenval('T')) { + e = parser.value_bool(); + } + filament_sensor.filament_param.enabled[e] = enable; + need_save = true; + } + + if (parser.seenval('D')) { + uint8_t d = parser.value_byte(); + if (d < 1) { + d = 1; + } + filament_sensor.filament_param.distance = d; + need_save = true; + } + + if (parser.seen('R') || need_save) { + if (need_save) + (void)settings.save(); + filament_sensor.reset(); + } + + SERIAL_ECHOLNPAIR("filament check enable T[0]:", filament_sensor.filament_param.enabled[0], + ", T[1]:", filament_sensor.filament_param.enabled[1]); + SERIAL_ECHOLNPAIR("filament check param - diatance:", filament_sensor.filament_param.distance); + SERIAL_ECHOLNPAIR("filament sensor value T[0]:", filament_sensor.get_adc_val(0), + ", T[1]:", filament_sensor.get_adc_val(1)); + } \ No newline at end of file diff --git a/Marlin/src/gcode/gcode.cpp b/Marlin/src/gcode/gcode.cpp index 62c1f5bb54..bc42820911 100644 --- a/Marlin/src/gcode/gcode.cpp +++ b/Marlin/src/gcode/gcode.cpp @@ -789,9 +789,9 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) { case 407: M407(); break; // M407: Display measured filament diameter #endif - #if HAS_FILAMENT_SENSOR - case 412: M412(); break; // M412: Enable/Disable filament runout detection - #endif + //#if HAS_FILAMENT_SENSOR + // case 412: M412(); break; // M412: Enable/Disable filament runout detection + //#endif case 412: M412(); break; // M412: Enable/Disable filament runout detection #if HAS_MULTI_LANGUAGE diff --git a/Marlin/src/gcode/gcode.h b/Marlin/src/gcode/gcode.h index 264ee8fb31..7ac2755772 100644 --- a/Marlin/src/gcode/gcode.h +++ b/Marlin/src/gcode/gcode.h @@ -906,9 +906,9 @@ class GcodeSuite { static void M407(); #endif - #if ENABLED(HAS_FILAMENT_SENSOR) - static void M412(); - #endif + //#if ENABLED(HAS_FILAMENT_SENSOR) + // static void M412(); + //#endif static void M412(); #if ENABLED(HAS_MULTI_LANGUAGE) diff --git a/Marlin/src/gcode/queue.cpp b/Marlin/src/gcode/queue.cpp index 290eae9c54..cd0cfa45f5 100644 --- a/Marlin/src/gcode/queue.cpp +++ b/Marlin/src/gcode/queue.cpp @@ -28,7 +28,7 @@ GCodeQueue queue; #include "gcode.h" - +#include "../feature/e_parser.h" #include "../lcd/marlinui.h" #include "../sd/cardreader.h" #include "../module/motion.h" @@ -389,7 +389,12 @@ inline bool process_line_done(uint8_t &sis, char (&buff)[MAX_CMD_SIZE], int &ind * Exit when the buffer is full or when no more characters are * left on the serial port. */ + void GCodeQueue::get_serial_commands() { + // Static Emergency Parser state for MSerial1 (port 0) + static EmergencyParser emergency_parser; + static EmergencyParser::State emergency_state = EmergencyParser::EP_RESET; + #if ENABLED(BINARY_FILE_TRANSFER) if (card.flag.binary_mode) { /** @@ -421,7 +426,7 @@ void GCodeQueue::get_serial_commands() { // Check if the queue is full and exit if it is. if (ring_buffer.full()) return; - // No data for this port ? Skip it + // No data for this port? Skip it if (!serial_data_available(p)) continue; // Ok, we have some data to process, let's make progress here @@ -441,8 +446,12 @@ void GCodeQueue::get_serial_commands() { const char serial_char = (char)c; SerialState &serial = serial_state[p]; - if (ISEOL(serial_char)) { + // Parse emergency commands for MSerial1 (port 0, USART1 for OctoPrint) + if (p == 0) { + emergency_parser.update(emergency_state, serial_char); + } + if (ISEOL(serial_char)) { // Reset our state, continue if the line was empty if (process_line_done(serial.input_state, serial.line_buffer, serial.count)) continue; @@ -453,7 +462,6 @@ void GCodeQueue::get_serial_commands() { char *npos = (*command == 'N') ? command : nullptr; // Require the N parameter to start the line if (npos) { - const bool M110 = !!strstr_P(command, PSTR("M110")); if (M110) { @@ -498,7 +506,6 @@ void GCodeQueue::get_serial_commands() { // // Movement commands give an alert when the machine is stopped // - if (IsStopped()) { char* gpos = strchr(command, 'G'); if (gpos) { diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 1978926ccb..546c312314 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -892,26 +892,26 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS * Filament Runout needs one or more pins and either SD Support or Auto print start detection */ #if HAS_FILAMENT_SENSOR - #if !PIN_EXISTS(FIL_RUNOUT) - #error "FILAMENT_RUNOUT_SENSOR requires FIL_RUNOUT_PIN." + #if !PIN_EXISTS(FIL_RUNOUT) && !defined(CUSTOM_FILAMENT_SENSOR) + #error "FILAMENT_RUNOUT_SENSOR requires FIL_RUNOUT_PIN unless CUSTOM_FILAMENT_SENSOR is defined." #elif HAS_PRUSA_MMU2 && NUM_RUNOUT_SENSORS != 1 - #error "NUM_RUNOUT_SENSORS must be 1 with MMU2 / MMU2S." - #elif NUM_RUNOUT_SENSORS != 1 && NUM_RUNOUT_SENSORS != E_STEPPERS - #error "NUM_RUNOUT_SENSORS must be either 1 or number of E steppers." - #elif NUM_RUNOUT_SENSORS >= 8 && !PIN_EXISTS(FIL_RUNOUT8) - #error "FIL_RUNOUT8_PIN is required with NUM_RUNOUT_SENSORS >= 8." - #elif NUM_RUNOUT_SENSORS >= 7 && !PIN_EXISTS(FIL_RUNOUT7) - #error "FIL_RUNOUT7_PIN is required with NUM_RUNOUT_SENSORS >= 7." - #elif NUM_RUNOUT_SENSORS >= 6 && !PIN_EXISTS(FIL_RUNOUT6) - #error "FIL_RUNOUT6_PIN is required with NUM_RUNOUT_SENSORS >= 6." - #elif NUM_RUNOUT_SENSORS >= 5 && !PIN_EXISTS(FIL_RUNOUT5) - #error "FIL_RUNOUT5_PIN is required with NUM_RUNOUT_SENSORS >= 5." - #elif NUM_RUNOUT_SENSORS >= 4 && !PIN_EXISTS(FIL_RUNOUT4) - #error "FIL_RUNOUT4_PIN is required with NUM_RUNOUT_SENSORS >= 4." - #elif NUM_RUNOUT_SENSORS >= 3 && !PIN_EXISTS(FIL_RUNOUT3) - #error "FIL_RUNOUT3_PIN is required with NUM_RUNOUT_SENSORS >= 3." - #elif NUM_RUNOUT_SENSORS >= 2 && !PIN_EXISTS(FIL_RUNOUT2) - #error "FIL_RUNOUT2_PIN is required with NUM_RUNOUT_SENSORS >= 2." + #error "NUM_RUNOUT_SENSORS must be 1 with MMU2 / MMU2S." + #elif NUM_RUNOUT_SENSORS != 1 && NUM_RUNOUT_SENSORS != E_STEPPERS && !defined(CUSTOM_FILAMENT_SENSOR) + #error "NUM_RUNOUT_SENSORS must be either 1 or number of E steppers unless CUSTOM_FILAMENT_SENSOR is defined." + #elif NUM_RUNOUT_SENSORS >= 8 && !PIN_EXISTS(FIL_RUNOUT8) && !defined(CUSTOM_FILAMENT_SENSOR) + #error "FIL_RUNOUT8_PIN is required with NUM_RUNOUT_SENSORS >= 8 unless CUSTOM_FILAMENT_SENSOR is defined." + #elif NUM_RUNOUT_SENSORS >= 7 && !PIN_EXISTS(FIL_RUNOUT7) && !defined(CUSTOM_FILAMENT_SENSOR) + #error "FIL_RUNOUT7_PIN is required with NUM_RUNOUT_SENSORS >= 7 unless CUSTOM_FILAMENT_SENSOR is defined." + #elif NUM_RUNOUT_SENSORS >= 6 && !PIN_EXISTS(FIL_RUNOUT6) && !defined(CUSTOM_FILAMENT_SENSOR) + #error "FIL_RUNOUT6_PIN is required with NUM_RUNOUT_SENSORS >= 6 unless CUSTOM_FILAMENT_SENSOR is defined." + #elif NUM_RUNOUT_SENSORS >= 5 && !PIN_EXISTS(FIL_RUNOUT5) && !defined(CUSTOM_FILAMENT_SENSOR) + #error "FIL_RUNOUT5_PIN is required with NUM_RUNOUT_SENSORS >= 5 unless CUSTOM_FILAMENT_SENSOR is defined." + #elif NUM_RUNOUT_SENSORS >= 4 && !PIN_EXISTS(FIL_RUNOUT4) && !defined(CUSTOM_FILAMENT_SENSOR) + #error "FIL_RUNOUT4_PIN is required with NUM_RUNOUT_SENSORS >= 4 unless CUSTOM_FILAMENT_SENSOR is defined." + #elif NUM_RUNOUT_SENSORS >= 3 && !PIN_EXISTS(FIL_RUNOUT3) && !defined(CUSTOM_FILAMENT_SENSOR) + #error "FIL_RUNOUT3_PIN is required with NUM_RUNOUT_SENSORS >= 3 unless CUSTOM_FILAMENT_SENSOR is defined." + #elif NUM_RUNOUT_SENSORS >= 2 && !PIN_EXISTS(FIL_RUNOUT2) && !defined(CUSTOM_FILAMENT_SENSOR) + #error "FIL_RUNOUT2_PIN is required with NUM_RUNOUT_SENSORS >= 2 unless CUSTOM_FILAMENT_SENSOR is defined." #elif BOTH(FIL_RUNOUT1_PULLUP, FIL_RUNOUT1_PULLDOWN) #error "You can't enable FIL_RUNOUT1_PULLUP and FIL_RUNOUT1_PULLDOWN at the same time." #elif BOTH(FIL_RUNOUT2_PULLUP, FIL_RUNOUT2_PULLDOWN) @@ -961,12 +961,25 @@ static_assert(Y_MAX_LENGTH >= Y_BED_SIZE, "Movement bounds (Y_MIN_POS, Y_MAX_POS #endif #if ENABLED(NOZZLE_PARK_FEATURE) - constexpr float npp[] = NOZZLE_PARK_POINT; - static_assert(COUNT(npp) == XYZ, "NOZZLE_PARK_POINT requires X, Y, and Z values."); - constexpr xyz_pos_t npp_xyz = NOZZLE_PARK_POINT; - static_assert(WITHIN(npp_xyz.x, X_MIN_POS, X_MAX_POS), "NOZZLE_PARK_POINT.X is out of bounds (X_MIN_POS, X_MAX_POS)."); - static_assert(WITHIN(npp_xyz.y, Y_MIN_POS, Y_MAX_POS), "NOZZLE_PARK_POINT.Y is out of bounds (Y_MIN_POS, Y_MAX_POS)."); - static_assert(WITHIN(npp_xyz.z, Z_MIN_POS, Z_MAX_POS), "NOZZLE_PARK_POINT.Z is out of bounds (Z_MIN_POS, Z_MAX_POS)."); + // Check NOZZLE_PARK_POINT_T0 + constexpr float npp_t0[] = NOZZLE_PARK_POINT_T0; + static_assert(COUNT(npp_t0) == XYZ, "NOZZLE_PARK_POINT_T0 requires X, Y, and Z values."); + constexpr xyz_pos_t npp_t0_xyz = NOZZLE_PARK_POINT_T0; + static_assert(WITHIN(npp_t0_xyz.x, X_MIN_POS, X_MAX_POS), "NOZZLE_PARK_POINT_T0.X is out of bounds (X_MIN_POS, X_MAX_POS)."); + static_assert(WITHIN(npp_t0_xyz.y, Y_MIN_POS, Y_MAX_POS), "NOZZLE_PARK_POINT_T0.Y is out of bounds (Y_MIN_POS, Y_MAX_POS)."); + static_assert(WITHIN(npp_t0_xyz.z, Z_MIN_POS, Z_MAX_POS), "NOZZLE_PARK_POINT_T0.Z is out of bounds (Z_MIN_POS, Z_MAX_POS)."); + + // Check NOZZLE_PARK_POINT_T1 + constexpr float npp_t1[] = NOZZLE_PARK_POINT_T1; + static_assert(COUNT(npp_t1) == XYZ, "NOZZLE_PARK_POINT_T1 requires X, Y, and Z values."); + constexpr xyz_pos_t npp_t1_xyz = NOZZLE_PARK_POINT_T1; + #if ENABLED(DUAL_X_CARRIAGE) + static_assert(WITHIN(npp_t1_xyz.x, X_MIN_POS, 340), "NOZZLE_PARK_POINT_T1.X is out of bounds (X_MIN_POS, hotend_offset[1].x)."); + #else + static_assert(WITHIN(npp_t1_xyz.x, X_MIN_POS, X_MAX_POS), "NOZZLE_PARK_POINT_T1.X is out of bounds (X_MIN_POS, X_MAX_POS)."); + #endif + static_assert(WITHIN(npp_t1_xyz.y, Y_MIN_POS, Y_MAX_POS), "NOZZLE_PARK_POINT_T1.Y is out of bounds (Y_MIN_POS, Y_MAX_POS)."); + static_assert(WITHIN(npp_t1_xyz.z, Z_MIN_POS, Z_MAX_POS), "NOZZLE_PARK_POINT_T1.Z is out of bounds (Z_MIN_POS, Z_MAX_POS)."); #endif /** diff --git a/Marlin/src/inc/Version.h b/Marlin/src/inc/Version.h index 5e414972d1..7a47841c57 100644 --- a/Marlin/src/inc/Version.h +++ b/Marlin/src/inc/Version.h @@ -21,7 +21,7 @@ */ #pragma once -#define J1_BUILD_VERSION "2.2.15" +#define J1_BUILD_VERSION "0.0.06" /** * Release version. Leave the Marlin version or apply a custom scheme. diff --git a/Marlin/src/libs/nozzle.cpp b/Marlin/src/libs/nozzle.cpp index e277216ab4..6517af84b4 100644 --- a/Marlin/src/libs/nozzle.cpp +++ b/Marlin/src/libs/nozzle.cpp @@ -20,7 +20,7 @@ * */ -#include "../inc/MarlinConfig.h" + #include "../inc/MarlinConfig.h" #if EITHER(NOZZLE_CLEAN_FEATURE, NOZZLE_PARK_FEATURE) @@ -226,18 +226,17 @@ Nozzle nozzle; #if ENABLED(NOZZLE_PARK_FEATURE) float Nozzle::park_mode_0_height(const_float_t park_z) { - // Apply a minimum raise, if specified. Use park.z as a minimum height instead. - return _MAX(park_z, // Minimum height over 0 based on input - _MIN(Z_MAX_POS, // Maximum height is fixed + return _MAX(park_z, + _MIN(Z_MAX_POS, #ifdef NOZZLE_PARK_Z_RAISE_MIN - NOZZLE_PARK_Z_RAISE_MIN + // Minimum raise... + NOZZLE_PARK_Z_RAISE_MIN + #endif - current_position.z // ...over current position + current_position.z ) ); } - void Nozzle::park(const uint8_t z_action, const xyz_pos_t &park/*=NOZZLE_PARK_POINT*/) { + void Nozzle::park(const uint8_t z_action, const xyz_pos_t &park) { constexpr feedRate_t fr_xy = NOZZLE_PARK_XY_FEEDRATE, fr_z = NOZZLE_PARK_Z_FEEDRATE; switch (z_action) { @@ -263,6 +262,14 @@ Nozzle nozzle; report_current_position(); } + xyz_pos_t Nozzle::get_park_point(uint8_t extruder) { + if (extruder == 0) { + return NOZZLE_PARK_POINT_T0; + } else { + return NOZZLE_PARK_POINT_T1; + } + } + #endif // NOZZLE_PARK_FEATURE -#endif // NOZZLE_CLEAN_FEATURE || NOZZLE_PARK_FEATURE +#endif // NOZZLE_CLEAN_FEATURE || NOZZLE_PARK_FEATURE \ No newline at end of file diff --git a/Marlin/src/libs/nozzle.h b/Marlin/src/libs/nozzle.h index 7bbd0e35c1..6426b8097a 100644 --- a/Marlin/src/libs/nozzle.h +++ b/Marlin/src/libs/nozzle.h @@ -32,61 +32,22 @@ class Nozzle { private: #if ENABLED(NOZZLE_CLEAN_FEATURE) - - /** - * @brief Stroke clean pattern - * @details Wipes the nozzle back and forth in a linear movement - * - * @param start xyz_pos_t defining the starting point - * @param end xyz_pos_t defining the ending point - * @param strokes number of strokes to execute - */ static void stroke(const xyz_pos_t &start, const xyz_pos_t &end, const uint8_t &strokes) _Os; - - /** - * @brief Zig-zag clean pattern - * @details Apply a zig-zag cleaning pattern - * - * @param start xyz_pos_t defining the starting point - * @param end xyz_pos_t defining the ending point - * @param strokes number of strokes to execute - * @param objects number of objects to create - */ static void zigzag(const xyz_pos_t &start, const xyz_pos_t &end, const uint8_t &strokes, const uint8_t &objects) _Os; - - /** - * @brief Circular clean pattern - * @details Apply a circular cleaning pattern - * - * @param start xyz_pos_t defining the middle of circle - * @param strokes number of strokes to execute - * @param radius radius of circle - */ static void circle(const xyz_pos_t &start, const xyz_pos_t &middle, const uint8_t &strokes, const_float_t radius) _Os; - - #endif // NOZZLE_CLEAN_FEATURE + #endif public: #if ENABLED(NOZZLE_CLEAN_FEATURE) - - /** - * @brief Clean the nozzle - * @details Starts the selected clean procedure pattern - * - * @param pattern one of the available patterns - * @param argument depends on the cleaning pattern - */ static void clean(const uint8_t &pattern, const uint8_t &strokes, const_float_t radius, const uint8_t &objects, const uint8_t cleans) _Os; - - #endif // NOZZLE_CLEAN_FEATURE + #endif #if ENABLED(NOZZLE_PARK_FEATURE) - static float park_mode_0_height(const_float_t park_z) _Os; - static void park(const uint8_t z_action, const xyz_pos_t &park=NOZZLE_PARK_POINT) _Os; - + static void park(const uint8_t z_action, const xyz_pos_t &park) _Os; + static xyz_pos_t get_park_point(uint8_t extruder); // New helper function #endif }; -extern Nozzle nozzle; +extern Nozzle nozzle; \ No newline at end of file diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index f5d14bbc69..bc4e159a66 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -576,7 +576,7 @@ void _O2 Endstops::report_states() { #if HAS_J_MAX ES_REPORT(J_MAX); #endif - #if HAS_K_MIN + #if HAS_K_MIN ES_REPORT(K_MIN); #endif #if HAS_K_MAX @@ -588,32 +588,38 @@ void _O2 Endstops::report_states() { #if HAS_CUSTOM_PROBE_PIN print_es_state(PROBE_TRIGGERED(), PSTR(STR_Z_PROBE)); #endif - #if MULTI_FILAMENT_SENSOR - #define _CASE_RUNOUT(N) case N: pin = FIL_RUNOUT##N##_PIN; state = FIL_RUNOUT##N##_STATE; break; - LOOP_S_LE_N(i, 1, NUM_RUNOUT_SENSORS) { - pin_t pin; - uint8_t state; - switch (i) { - default: continue; - REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_RUNOUT) - } - SERIAL_ECHOPGM(STR_FILAMENT_RUNOUT_SENSOR); - if (i > 1) SERIAL_CHAR(' ', '0' + i); - print_es_state(extDigitalRead(pin) != state); - } - #undef _CASE_RUNOUT - #elif HAS_FILAMENT_SENSOR - print_es_state(READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE, PSTR(STR_FILAMENT_RUNOUT_SENSOR)); + + #if HAS_FILAMENT_SENSOR + #ifdef CUSTOM_FILAMENT_SENSOR + print_es_state(filament_sensor.is_trigger(0), PSTR("filament_0")); + print_es_state(filament_sensor.is_trigger(1), PSTR("filament_1")); + #else + #if MULTI_FILAMENT_SENSOR + #define _CASE_RUNOUT(N) case N: pin = FIL_RUNOUT##N##_PIN; state = FIL_RUNOUT##N##_STATE; break; + LOOP_S_LE_N(i, 1, NUM_RUNOUT_SENSORS) { + pin_t pin; + uint8_t state; + switch (i) { + default: continue; + REPEAT_1(NUM_RUNOUT_SENSORS, _CASE_RUNOUT) + } + SERIAL_ECHOPGM(STR_FILAMENT_RUNOUT_SENSOR); + if (i > 1) SERIAL_CHAR(' ', '0' + i); + print_es_state(extDigitalRead(pin) != state, PSTR(STR_FILAMENT_RUNOUT_SENSOR)); + } + #undef _CASE_RUNOUT + #else + print_es_state(READ(FIL_RUNOUT1_PIN) != FIL_RUNOUT1_STATE, PSTR(STR_FILAMENT_RUNOUT_SENSOR)); + #endif + #endif #endif - print_es_state(switch_detect.read_e0_probe_status(), "PROBE_0"); - print_es_state(switch_detect.read_e1_probe_status(), "PROBE_1"); - print_es_state(filament_sensor.is_trigger(0), "filament_0"); - print_es_state(filament_sensor.is_trigger(1), "filament_1"); - print_es_state(power_loss.is_power_220v_pin_trigger(), "220V_power_loss"); + print_es_state(switch_detect.read_e0_probe_status(), PSTR("PROBE_0")); + print_es_state(switch_detect.read_e1_probe_status(), PSTR("PROBE_1")); + print_es_state(power_loss.is_power_220v_pin_trigger(), PSTR("220V_power_loss")); + TERN_(BLTOUCH, bltouch._reset_SW_mode()); TERN_(JOYSTICK_DEBUG, joystick.report()); - } // Endstops::report_states // The following routines are called from an ISR context. It could be the temperature ISR, the diff --git a/Marlin/src/module/stepper.cpp b/Marlin/src/module/stepper.cpp index cb67676da1..b8f6def07b 100644 --- a/Marlin/src/module/stepper.cpp +++ b/Marlin/src/module/stepper.cpp @@ -1832,7 +1832,6 @@ void Stepper::pulse_phase_isr() { // set_directions(current_direction_bits); // } - if (current_direction_bits != last_direction_bits) { // TERN_(HAS_MULTI_EXTRUDER, last_moved_extruder = stepper_extruder); // TERN_(HAS_L64XX, L64XX_OK_to_power_up = true); @@ -1856,6 +1855,8 @@ void Stepper::pulse_phase_isr() { PULSE_START(E); // PULSE_PREP(E); current_block_e_position += count_direction[E_AXIS]; + filament_sensor.e0_step(active_extruder == 0 ? count_direction[E_AXIS] : 0); // [NEW] + filament_sensor.e1_step(active_extruder == 1 ? count_direction[E_AXIS] : 0); // [NEW] PULSE_STOP(E); } diff --git a/Marlin/src/module/temperature.cpp b/Marlin/src/module/temperature.cpp index 716fbf0979..0cd7ffc4fa 100644 --- a/Marlin/src/module/temperature.cpp +++ b/Marlin/src/module/temperature.cpp @@ -27,6 +27,8 @@ // Useful when debugging thermocouples //#define IGNORE_THERMOCOUPLE_ERRORS +//#include "../../feature/runout.h" // For FilamentMonitor +//#include "../../../snapmaker/module/system.h" // For system_service #include "../MarlinCore.h" #include "../HAL/shared/Delay.h" #include "../lcd/marlinui.h" @@ -1290,82 +1292,100 @@ void Temperature::min_temp_error(const heater_id_t heater_id) { * - Apply filament width to the extrusion rate (may move) * - Update the heated bed PID output value */ -void Temperature::manage_heater() { - extern uint32_t feed_dog_time; - feed_dog_time = millis(); - if (marlin_state == MF_INITIALIZING) return watchdog_refresh(); // If Marlin isn't started, at least reset the watchdog! - - #if ENABLED(EMERGENCY_PARSER) - if (emergency_parser.killed_by_M112) kill(M112_KILL_STR, nullptr, true); - - if (emergency_parser.quickstop_by_M410) { - emergency_parser.quickstop_by_M410 = false; // quickstop_stepper may call idle so clear this now! - quickstop_stepper(); - } - #endif - - if (!updateTemperaturesIfReady()) return; // Will also reset the watchdog if temperatures are ready - - #if DISABLED(IGNORE_THERMOCOUPLE_ERRORS) - #if TEMP_SENSOR_0_IS_MAX_TC - if (degHotend(0) > _MIN(HEATER_0_MAXTEMP, TEMP_SENSOR_0_MAX_TC_TMAX - 1.0)) max_temp_error(H_E0); - if (degHotend(0) < _MAX(HEATER_0_MINTEMP, TEMP_SENSOR_0_MAX_TC_TMIN + .01)) min_temp_error(H_E0); - #endif - #if TEMP_SENSOR_1_IS_MAX_TC - if (degHotend(1) > _MIN(HEATER_1_MAXTEMP, TEMP_SENSOR_1_MAX_TC_TMAX - 1.0)) max_temp_error(H_E1); - if (degHotend(1) < _MAX(HEATER_1_MINTEMP, TEMP_SENSOR_1_MAX_TC_TMIN + .01)) min_temp_error(H_E1); - #endif - #if TEMP_SENSOR_REDUNDANT_IS_MAX_TC - if (degRedundant() > TEMP_SENSOR_REDUNDANT_MAX_TC_TMAX - 1.0) max_temp_error(H_REDUNDANT); - if (degRedundant() < TEMP_SENSOR_REDUNDANT_MAX_TC_TMIN + .01) min_temp_error(H_REDUNDANT); - #endif - #endif - - millis_t ms = millis(); - - #if HAS_HOTEND - - HOTEND_LOOP() { - #if ENABLED(THERMAL_PROTECTION_HOTENDS) - if (degHotend(e) > temp_range[e].maxtemp) { - // turn off power of toolheads - WRITE(HEATER_PWR_PIN, LOW); - max_temp_error((heater_id_t)e); - } else { - // turn on power of toolheads - WRITE(HEATER_PWR_PIN, HIGH); - // exception_server.clean_exception((exception_type_e)(EXCEPTION_TYPE_LEFT_NOZZLE_TEMP+e)); - } - #endif - - TERN_(HEATER_IDLE_HANDLER, heater_idle[e].update(ms)); - - #if ENABLED(THERMAL_PROTECTION_HOTENDS) - // Check for thermal runaway - tr_state_machine[e].run(temp_hotend[e].celsius, temp_hotend[e].target, (heater_id_t)e, THERMAL_PROTECTION_PERIOD, THERMAL_PROTECTION_HYSTERESIS); - #endif - - // nozzle pid_autoturn does not allow pwm modification based on target temperature - if (!is_nozzle_pid_autoturn_run()) - temp_hotend[e].soft_pwm_amount = (temp_hotend[e].celsius > temp_range[e].mintemp || is_preheating(e)) && temp_hotend[e].celsius < temp_range[e].maxtemp ? (int)get_pid_output_hotend(e) >> 1 : 0; - - #if WATCH_HOTENDS - // Make sure temperature is increasing - if (watch_hotend[e].elapsed(ms)) { // Enabled and time to check? - if (watch_hotend[e].check(degHotend(e))) { // Increased enough? - start_watching_hotend(e); // If temp reached, turn off elapsed check - } - else { - TERN_(DWIN_CREALITY_LCD, DWIN_Popup_Temperature(0)); - _temp_error((heater_id_t)e, str_t_heating_failed, GET_TEXT(MSG_HEATING_FAILED_LCD)); - exception_server.trigger_exception((exception_type_e)(EXCEPTION_TYPE_LEFT_NOZZLE_TEMP_TIMEOUT+e)); - } - } - #endif - } // HOTEND_LOOP - - #endif // HAS_HOTEND + + void Temperature::manage_heater() { + extern uint32_t feed_dog_time; + feed_dog_time = millis(); + if (marlin_state == MF_INITIALIZING) return watchdog_refresh(); // If Marlin isn't started, at least reset the watchdog! + + #if ENABLED(EMERGENCY_PARSER) + if (emergency_parser.killed_by_M112) kill(M112_KILL_STR, nullptr, true); + + if (emergency_parser.quickstop_by_M410) { + emergency_parser.quickstop_by_M410 = false; // quickstop_stepper may call idle so clear this now! + quickstop_stepper(); + } + #endif + + if (!updateTemperaturesIfReady()) return; // Will also reset the watchdog if temperatures are ready + + #if DISABLED(IGNORE_THERMOCOUPLE_ERRORS) + #if TEMP_SENSOR_0_IS_MAX_TC + if (degHotend(0) > _MIN(HEATER_0_MAXTEMP, TEMP_SENSOR_0_MAX_TC_TMAX - 1.0)) max_temp_error(H_E0); + if (degHotend(0) < _MAX(HEATER_0_MINTEMP, TEMP_SENSOR_0_MAX_TC_TMIN + .01)) min_temp_error(H_E0); + #endif + #if TEMP_SENSOR_1_IS_MAX_TC + if (degHotend(1) > _MIN(HEATER_1_MAXTEMP, TEMP_SENSOR_1_MAX_TC_TMAX - 1.0)) max_temp_error(H_E1); + if (degHotend(1) < _MAX(HEATER_1_MINTEMP, TEMP_SENSOR_1_MAX_TC_TMIN + .01)) min_temp_error(H_E1); + #endif + #if TEMP_SENSOR_REDUNDANT_IS_MAX_TC + if (degRedundant() > TEMP_SENSOR_REDUNDANT_MAX_TC_TMAX - 1.0) max_temp_error(H_REDUNDANT); + if (degRedundant() < TEMP_SENSOR_REDUNDANT_MAX_TC_TMIN + .01) min_temp_error(H_REDUNDANT); + #endif + #endif + + millis_t ms = millis(); + + #if HAS_HOTEND + + HOTEND_LOOP() { + #if ENABLED(THERMAL_PROTECTION_HOTENDS) + if (degHotend(e) > temp_range[e].maxtemp) { + // turn off power of toolheads + WRITE(HEATER_PWR_PIN, LOW); + max_temp_error((heater_id_t)e); + } else { + // turn on power of toolheads + WRITE(HEATER_PWR_PIN, HIGH); + // exception_server.clean_exception((exception_type_e)(EXCEPTION_TYPE_LEFT_NOZZLE_TEMP+e)); + } + #endif + + TERN_(HEATER_IDLE_HANDLER, heater_idle[e].update(ms)); + + #if ENABLED(THERMAL_PROTECTION_HOTENDS) + // Check for thermal runaway + tr_state_machine[e].run(temp_hotend[e].celsius, temp_hotend[e].target, (heater_id_t)e, THERMAL_PROTECTION_PERIOD, THERMAL_PROTECTION_HYSTERESIS); + #endif + + // nozzle pid_autoturn does not allow pwm modification based on target temperature + if (!is_nozzle_pid_autoturn_run()) + temp_hotend[e].soft_pwm_amount = (temp_hotend[e].celsius > temp_range[e].mintemp || is_preheating(e)) && temp_hotend[e].celsius < temp_range[e].maxtemp ? (int)get_pid_output_hotend(e) >> 1 : 0; + + #if WATCH_HOTENDS + // Make sure temperature is increasing + if (watch_hotend[e].elapsed(ms)) { // Enabled and time to check? + if (watch_hotend[e].check(degHotend(e))) { // Increased enough? + start_watching_hotend(e); // If temp reached, turn off elapsed check + } + else { + TERN_(DWIN_CREALITY_LCD, DWIN_Popup_Temperature(0)); + _temp_error((heater_id_t)e, str_t_heating_failed, GET_TEXT(MSG_HEATING_FAILED_LCD)); + exception_server.trigger_exception((exception_type_e)(EXCEPTION_TYPE_LEFT_NOZZLE_TEMP_TIMEOUT+e)); + } + } + #endif + } // HOTEND_LOOP + + // Check filament sensor status + //#if HAS_FILAMENT_SENSOR + // filament_sensor.check(); // Poll the filament sensor + // HOTEND_LOOP() { + // if (filament_sensor.is_trigger(e)) { + // if (!runout.is_triggered(e)) { + // runout.runout_detected(e); + // system_service.set_status(SYSTEM_STATUE_PAUSING, SYSTEM_STATUE_SCOURCE_FILAMENT); + // } + // } + // else { + // runout.set_triggered(e, false); + // } + // } + //#endif + + #endif // HAS_HOTEND + #if HAS_TEMP_REDUNDANT // Make sure measured temperatures are close together if (ABS(degRedundantTarget() - degRedundant()) > TEMP_SENSOR_REDUNDANT_MAX_DIFF) diff --git a/platformio.ini b/platformio.ini index 1b20fd2eb1..8c5a1b9144 100644 --- a/platformio.ini +++ b/platformio.ini @@ -145,15 +145,11 @@ extra_scripts = ${common.extra_scripts} build_flags = ${common.build_flags} lib_deps = ${common.lib_deps} monitor_speed = 250000 -monitor_flags = - --quiet - --echo - --eol - LF - --filter - colorize - --filter - time +monitor_echo = yes +monitor_eol = LF +monitor_filters = + colorize + time # # Just print the dependency tree @@ -206,5 +202,14 @@ build_src_filter = ${common.default_src_filter} +<../CrashCatcher/Core/src/CrashCatcher_armv7m.S> +<../CrashCatcher/port/*> +<../CrashCatcher/HexDump/src> + +<../Marlin/src/feature/host_actions.cpp> + +<../Marlin/src/feature/e_parser.cpp> -<../Marlin/src/gcode/control/M108_*.cpp> + +<../Marlin/src/gcode/motion/M290.cpp> +<../Marlin/src/feature/babystep.cpp> + +<../Marlin/src/feature/pause.cpp> + +<../Marlin/src/feature/runout.cpp> + +<../Marlin/src/libs/nozzle.cpp> + + + monitor_speed = 250000 -debug_tool = jlink \ No newline at end of file +debug_tool = jlink diff --git a/release/J1_MC_APP_V0.0.06_20250705.bin b/release/J1_MC_APP_V0.0.06_20250705.bin new file mode 100644 index 0000000000..6aecfcab73 Binary files /dev/null and b/release/J1_MC_APP_V0.0.06_20250705.bin differ diff --git a/release/J1_V0.0.06_20250705.bin b/release/J1_V0.0.06_20250705.bin new file mode 100644 index 0000000000..e6157096e3 Binary files /dev/null and b/release/J1_V0.0.06_20250705.bin differ diff --git a/snapmaker/J1/J1.cpp b/snapmaker/J1/J1.cpp index e75e18e3ad..a9b5425b3c 100644 --- a/snapmaker/J1/J1.cpp +++ b/snapmaker/J1/J1.cpp @@ -318,8 +318,8 @@ void step_isr_usage_log(void) { last_log_tick = millis(); if (need_log) { - LOG_E("### max_stepper_isr_usage %.2f%\r\n", max_stepper_isr_usage); - LOG_E("### max_stepper_isr_delay %d us\r\n", max_stepper_isr_delay / STEPPER_TIMER_TICKS_PER_US); + LOG_V("### max_stepper_isr_usage %.2f%\r\n", max_stepper_isr_usage); + LOG_V("### max_stepper_isr_delay %d us\r\n", max_stepper_isr_delay / STEPPER_TIMER_TICKS_PER_US); need_log = false; } } @@ -458,11 +458,11 @@ void j1_main_task(void *args) { if (ELAPSED(millis(), syslog_timeout)) { syslog_timeout = millis() + 20000; - LOG_I("%s: c0: %d/t0: %d, c1: %d/t1: %d, cb: %d/tb: %d, ", J1_BUILD_VERSION, + LOG_V("%s: c0: %d/t0: %d, c1: %d/t1: %d, cb: %d/tb: %d, ", J1_BUILD_VERSION, (int)thermalManager.degHotend(0), thermalManager.degTargetHotend(0), (int)thermalManager.degHotend(1), thermalManager.degTargetHotend(1), (int)thermalManager.degBed(), thermalManager.degTargetBed()); - LOG_I("sta: %u, excep sta: 0x%x, excep beh: 0x%x\n", system_service.get_status(), + LOG_V("sta: %u, excep sta: 0x%x, excep beh: 0x%x\n", system_service.get_status(), exception_server.get_exception(), exception_server.get_behavior()); } diff --git a/snapmaker/debug/debug.cpp b/snapmaker/debug/debug.cpp index ba9d4e4a79..f798b45597 100644 --- a/snapmaker/debug/debug.cpp +++ b/snapmaker/debug/debug.cpp @@ -29,7 +29,7 @@ #include "../module/exception.h" #include "../module/motion_control.h" #include "../module/print_control.h" -#include "../j1/switch_detect.h" +#include "../J1/switch_detect.h" #include "../module/enclosure.h" #include "../../Marlin/src/inc/Version.h" #include "../../Marlin/src/module/motion.h" diff --git a/snapmaker/gcode/contorl/M2000.cpp b/snapmaker/gcode/contorl/M2000.cpp index 91ae8bf231..e99ccbad08 100644 --- a/snapmaker/gcode/contorl/M2000.cpp +++ b/snapmaker/gcode/contorl/M2000.cpp @@ -19,366 +19,318 @@ * along with this program. If not, see . */ -#include "../../event/event.h" -#include "../../debug/debug.h" -#include "../../../Marlin/src/core/macros.h" -#include "../../../Marlin/src/gcode/gcode.h" -#include "../../../Marlin/src/module/endstops.h" -#include "../../../Marlin/src/module/stepper.h" -#include "../../module/motion_control.h" -#include "../../module/print_control.h" -#include "../../module/power_loss.h" -#include "../../module/system.h" -#include "../../J1/switch_detect.h" -#include "../../module/factory_data.h" -#include "../../module/calibtration.h" -#include - -/** - * S5 P0/1 - */ -void GcodeSuite::M2000() { - uint8_t s = (uint8_t)parser.byteval('S', (uint8_t)0xFF); - switch (s) { - case 1: - debug.show_all_status(); - extern void log_reset_source(void); - log_reset_source(); - break; - case 2: - WRITE(E0_AUTO_FAN_PIN, 1); - break; - case 3: - WRITE(E1_AUTO_FAN_PIN, 1); - break; - case 4: - WRITE(CHAMBER_AUTO_FAN_PIN, 1); - break; - case 5: - { // set pc protocol - event_handler.recv_enable(EVENT_SOURCE_MARLIN); - } - break; - case 6: - WRITE(MOTOR_PWR_PIN, 1); - WRITE(HEATER_PWR_PIN, 1); - WRITE(HEATER_BED_PWR_PIN, 1); - break; - case 7: - WRITE(MOTOR_PWR_PIN, 0); - WRITE(HEATER_PWR_PIN, 0); - WRITE(HEATER_BED_PWR_PIN, 0); - break; - case 8: - { - uint8_t dl = parser.byteval('D', SNAP_DEBUG_LEVEL_INFO); - debug.set_level((debug_level_e)dl); - } - break; - - case 10: - // endstops.echo(); - LOG_I("X: %d\r\n", stepper.triggered_position(X_AXIS)); - LOG_I("Y: %d\r\n", stepper.triggered_position(Y_AXIS)); - LOG_I("Z: %d\r\n", stepper.triggered_position(Z_AXIS)); - break; - - case 11: - { - quickstop_stepper(); - dual_x_carriage_mode = DXC_FULL_CONTROL_MODE; - set_duplication_enabled(false); - } - break; - - case 12: - { - uint8_t e = (uint8_t)parser.byteval('E', (uint8_t)0); - uint8_t dir = (uint8_t)parser.byteval('D', (uint8_t)1); - float feedrate_mm_m = (float)parser.byteval('F', (float)20.0); - if (fabs(feedrate_mm_m) > EPSILON) - stepper.start_only_extrude(e, dir, 50, feedrate_mm_m); - else - stepper.stop_only_extrude(e); - } - break; - - case 13: - { - // stepper.report_a_position(planner.position); - LOG_I("E_COUNT: %d\r\n", stepper.position(E_AXIS)); - } - break; - - case 14: - { - print_control.z_home_sg = (uint8_t)parser.byteval('Z', (uint8_t)0); - LOG_I("Z home sg set to %d\r\n", print_control.z_home_sg); - } - break; - - case 100: - LOG_I("test watch dog!\n"); - vTaskDelay(pdMS_TO_TICKS(1000)); - taskENTER_CRITICAL(); - while(1); - taskEXIT_CRITICAL(); - break; - - case 101: - LOG_I("test crash!\n"); - vTaskDelay(pdMS_TO_TICKS(10)); - *((uint32_t *)0) = 1234; - break; - - case 102: - { - SERIAL_ECHOLNPGM("\r\n ========= dump start ========= \r\n"); - uint8_t *p_crash_data_char = (uint8_t *)CRASH_DATA_FLASH_ADDR; - for (uint32_t i = 0; i < CRASH_DATA_SIZE; i++) { - SERIAL_IMPL.write(p_crash_data_char[i]); - } - SERIAL_ECHOLNPGM("\r\n========= crash dump end ========= \r\n"); - } - break; - - case 103: - { - SERIAL_ECHOLNPGM("\r\n ========= erase crash dump ========= \r\n"); - FLASH_Unlock(); - FLASH_ErasePage(CRASH_DATA_FLASH_ADDR); - FLASH_ErasePage(CRASH_DATA_FLASH_ADDR + APP_FLASH_PAGE_SIZE); - FLASH_Lock(); - } - break; - - case 104: - { - if(parser.seen('X')) { - LOG_I("X speed %f mms\r\n", axisManager.axis[0].getCurrentSpeedMMs()); - } - else if(parser.seen('Y')) { - LOG_I("Y speed %f mms\r\n", axisManager.axis[1].getCurrentSpeedMMs()); - } - else if(parser.seen('Z')) { - LOG_I("Z speed %f mms\r\n", axisManager.axis[2].getCurrentSpeedMMs()); - } - } - break; - - case 105: - { - uint32_t gcode_jumper_line = parser.longval('J', 0x0); - if (gcode_jumper_line) { - power_loss.next_req = gcode_jumper_line; - } - } - break; - - case 110: - { - LOG_I("Erase factory data\r\n"); - // fd_srv.reset(); - // fd_srv.save(); - // fd_srv.log(); - fd_srv.erase(); - } - break; - - case 111: - { - LOG_I("Set factory build plate thickness data\r\n"); - float bpt = (float)parser.floatval('B', (float)5.0); - if (fd_srv.setBuildPlateThickness(bpt) && fd_srv.save()) { - fd_srv.log(); - calibtration.updateBuildPlateThicknessWithHomeOffset(bpt); - } - else { - LOG_W("Build plate thickness is not valid\n\n"); - } - } - break; - - case 112: - { - fd_srv.log(); - } - break; - - case 113: - { - uint8_t pnm = parser.byteval('M', 0xFF); - print_control.set_noise_mode(print_noise_mode_e(pnm)); - } - break; - - case 114: - { - LOG_I("print noise mode %u\n", (uint8_t)print_control.get_noise_mode()); + #include "../../event/event.h" + #include "../../debug/debug.h" + #include "../../../Marlin/src/core/macros.h" + #include "../../../Marlin/src/gcode/gcode.h" + #include "../../../Marlin/src/module/endstops.h" + #include "../../../Marlin/src/module/stepper.h" + #include "../../module/motion_control.h" + #include "../../module/print_control.h" + #include "../../module/power_loss.h" + #include "../../module/system.h" + #include "../../J1/switch_detect.h" + #include "../../module/factory_data.h" + #include "../../module/calibtration.h" + #include + #include "../../Marlin/src/inc/MarlinConfig.h" + #include "../../Marlin/src/module/planner.h" + #include "../../Marlin/src/module/motion.h" + #include "../../../Marlin/src/module/printcounter.h" + + extern bool is_hmi_printing; + + void GcodeSuite::M2000() { + uint8_t s = (uint8_t)parser.byteval('S', (uint8_t)0xFF); + + switch (s) { + case 1: + debug.show_all_status(); + extern void log_reset_source(void); + log_reset_source(); + break; + case 2: + WRITE(E0_AUTO_FAN_PIN, 1); + break; + case 3: + WRITE(E1_AUTO_FAN_PIN, 1); + break; + case 4: + WRITE(CHAMBER_AUTO_FAN_PIN, 1); + break; + case 5: + { event_handler.recv_enable(EVENT_SOURCE_MARLIN); } + break; + case 6: + WRITE(MOTOR_PWR_PIN, 1); + WRITE(HEATER_PWR_PIN, 1); + WRITE(HEATER_BED_PWR_PIN, 1); + break; + case 7: + WRITE(MOTOR_PWR_PIN, 0); + WRITE(HEATER_PWR_PIN, 0); + WRITE(HEATER_BED_PWR_PIN, 0); + break; + case 8: + { + uint8_t dl = parser.byteval('D', SNAP_DEBUG_LEVEL_INFO); + debug.set_level((debug_level_e)dl); + } + break; + case 10: + LOG_I("X: %d\r\n", stepper.triggered_position(X_AXIS)); + LOG_I("Y: %d\r\n", stepper.triggered_position(Y_AXIS)); + LOG_I("Z: %d\r\n", stepper.triggered_position(Z_AXIS)); + break; + case 11: + { + quickstop_stepper(); + dual_x_carriage_mode = DXC_FULL_CONTROL_MODE; + set_duplication_enabled(false); + } + break; + case 12: + { + uint8_t e = (uint8_t)parser.byteval('E', (uint8_t)0); + uint8_t dir = (uint8_t)parser.byteval('D', (uint8_t)1); + float feedrate_mm_m = (float)parser.byteval('F', (float)20.0); + if (fabs(feedrate_mm_m) > EPSILON) + stepper.start_only_extrude(e, dir, 50, feedrate_mm_m); + else + stepper.stop_only_extrude(e); + } + break; + case 13: + { LOG_I("E_COUNT: %d\r\n", stepper.position(E_AXIS)); } + break; + case 14: + { + print_control.z_home_sg = (uint8_t)parser.byteval('Z', (uint8_t)0); + LOG_I("Z home sg set to %d\r\n", print_control.z_home_sg); + } + break; + case 100: + LOG_I("test watch dog!\n"); + vTaskDelay(pdMS_TO_TICKS(1000)); + taskENTER_CRITICAL(); + while(1); + taskEXIT_CRITICAL(); + break; + case 101: + LOG_I("test crash!\n"); + vTaskDelay(pdMS_TO_TICKS(10)); + *((uint32_t *)0) = 1234; + break; + case 102: + { + SERIAL_ECHOLNPGM("\r\n ========= dump start ========= \r\n"); + uint8_t *p_crash_data_char = (uint8_t *)CRASH_DATA_FLASH_ADDR; + for (uint32_t i = 0; i < CRASH_DATA_SIZE; i++) { + SERIAL_IMPL.write(p_crash_data_char[i]); + } + SERIAL_ECHOLNPGM("\r\n========= crash dump end ========= \r\n"); + } + break; + case 103: + { + SERIAL_ECHOLNPGM("\r\n ========= erase crash dump ========= \r\n"); + FLASH_Unlock(); + FLASH_ErasePage(CRASH_DATA_FLASH_ADDR); + FLASH_ErasePage(CRASH_DATA_FLASH_ADDR + APP_FLASH_PAGE_SIZE); + FLASH_Lock(); + } + break; + case 104: + { + if (parser.seen('X')) LOG_I("X speed %f mms\r\n", axisManager.axis[0].getCurrentSpeedMMs()); + else if (parser.seen('Y')) LOG_I("Y speed %f mms\r\n", axisManager.axis[1].getCurrentSpeedMMs()); + else if (parser.seen('Z')) LOG_I("Z speed %f mms\r\n", axisManager.axis[2].getCurrentSpeedMMs()); + } + break; + case 105: + { + uint32_t gcode_jumper_line = parser.longval('J', 0x0); + if (gcode_jumper_line) power_loss.next_req = gcode_jumper_line; + } + break; + case 110: + { LOG_I("Erase factory data\r\n"); fd_srv.erase(); } + break; + case 111: + { + LOG_I("Set factory build plate thickness data\r\n"); + float bpt = (float)parser.floatval('B', (float)5.0); + if (fd_srv.setBuildPlateThickness(bpt) && fd_srv.save()) { + fd_srv.log(); + calibtration.updateBuildPlateThicknessWithHomeOffset(bpt); + } + else { + LOG_W("Build plate thickness is not valid\n\n"); + } + } + break; + case 112: + { fd_srv.log(); } + break; + case 113: + { + uint8_t pnm = parser.byteval('M', 0xFF); + print_control.set_noise_mode(print_noise_mode_e(pnm)); + } + break; + case 114: + { LOG_I("print noise mode %u\n", (uint8_t)print_control.get_noise_mode()); } + break; + case 115: + { LOG_I("trun on probe power\n"); switch_detect.trun_on_probe_pwr(); } + break; + case 116: + { LOG_I("trun off probe power\n"); switch_detect.trun_off_probe_pwr(); } + break; + case 200: + if (!is_hmi_printing) { + const float speed = parser.floatval('V', planner.settings.max_feedrate_mm_s[X_AXIS]); + const float accel = parser.floatval('A', planner.settings.max_acceleration_mm_per_s2[X_AXIS]); + const uint8_t inactive_ext = active_extruder == 0 ? 1 : 0; + + SERIAL_ECHOLNPAIR("M2000 S200: Speed=", speed); + SERIAL_ECHOLNPAIR("M2000 S200: Accel=", accel); + + if (!print_job_timer.isRunning()) { + SERIAL_ECHOLNPGM("M2000 S200: Not printing, cannot move extruder"); + return; } - break; - - case 115: - { - LOG_I("trun on probe power\n"); - switch_detect.trun_on_probe_pwr(); - } - break; - - case 116: - { - LOG_I("trun off probe power\n"); - switch_detect.trun_off_probe_pwr(); + if (dual_x_carriage_mode > DXC_FULL_CONTROL_MODE) { + SERIAL_ECHOLNPGM("M2000 S200: Duplication or mirror mode not supported"); + return; } - break; - - case 200: - { - if (print_control.get_mode() >= PRINT_DUPLICATION_MODE) { - LOG_I("work mode do not support this command\r\n"); - return; - } - - if (axisManager.T0_T1_simultaneously_move) { - LOG_I("BUSY\r\n"); - return; - } - - if (SYSTEM_STATUE_PRINTING != system_service.get_status()) { - LOG_I("Not printing, can not move T0 T1 now\r\n"); - return; - } - - axisManager.T0_T1_simultaneously_move_req = true; - axisManager.T0_T1_target_pos = x_home_pos(!active_extruder); - float L = axisManager.T0_T1_target_pos - inactive_extruder_x; - float V = (float)parser.floatval('V', (float)200.0); - float A = (float)parser.floatval('A', (float)6000.0); - - int32_t target_steps = (!active_extruder) == 0 ? axisManager.X0_home_step_pos : axisManager.X1_home_step_pos; - axisManager.T0_T1_calc_steps = target_steps - axisManager.inactive_x_step_pos; - int32_t float_d_to_step_d = L * planner.settings.axis_steps_per_mm[X_AXIS]; - if (abs(float_d_to_step_d - axisManager.T0_T1_calc_steps) > 5) { - // LOG_E("Differ of float_d_to_step_d and axisManager.T0_T1_calc_steps too large, the inavtive X may has been move unexpected\r\n"); - axisManager.T0_T1_calc_steps = L * planner.settings.axis_steps_per_mm[X_AXIS]; - } - - // LOG_I("### M2000 S200: target_step_pos %d, current X step pos\r\n", target_steps, axisManager.inactive_x_step_pos); - // LOG_I("### M2000 S200: axisManager.T0_T1_calc_steps = %d, run float distance %f\r\n", axisManager.T0_T1_calc_steps, L); - if (0 == axisManager.T0_T1_calc_steps){ - axisManager.T0_T1_simultaneously_move_req = false; - // LOG_I("Cancel M2000 S200\r\n"); - return; - } - float millimeters = fabs(L); // mm - float entry_speed = 5 / 1000.0f; // mm / s - float leave_speed = 5 / 1000.0f; // mm / s - float nominal_speed = fabs(V) / 1000.0f; // mm / ms - float acceleration = fabs(A) / 1000000.0f; // mm / ms^2 - float i_acceleration = 1.0f / acceleration; - float i_nominal_speed = 1.0f / nominal_speed; + const float saved_accel = planner.settings.acceleration; + const uint8_t saved_ext = active_extruder; + planner.settings.acceleration = accel; - float accelDistance = Planner::estimate_acceleration_distance(entry_speed, nominal_speed, acceleration); - float decelDistance = Planner::estimate_acceleration_distance(nominal_speed, leave_speed, -acceleration); - if (accelDistance < EPSILON) { - accelDistance = 0; - } - if (decelDistance < EPSILON) { - decelDistance = 0; - } - float plateau = millimeters - accelDistance - decelDistance; + //SET_SOFT_ENDSTOP_LOOSE(true); // Disable software endstops for tool change - float accelClocks = (nominal_speed - entry_speed) * i_acceleration; - float decelClocks = (nominal_speed - leave_speed) * i_acceleration; - float plateauClocks = plateau * i_nominal_speed; + active_extruder = inactive_ext; + current_position.x = inactive_extruder_x; + planner.set_position_mm(current_position); + const float target_x = x_home_pos(inactive_ext); + SERIAL_ECHOLNPAIR("M2000 S200: Moving T", inactive_ext, " to X=", target_x); + do_blocking_move_to_x(target_x, speed); + inactive_extruder_x = target_x; - if (plateau < 0) { + active_extruder = saved_ext; + current_position.x = x_home_pos(saved_ext); // T0 at -13, T1 at 338.30 + planner.set_position_mm(current_position); + planner.settings.acceleration = saved_accel; - float newAccelDistance = Planner::intersection_distance(entry_speed, leave_speed, acceleration, millimeters); - if (newAccelDistance > millimeters) { - newAccelDistance = millimeters; - } - if (newAccelDistance < EPSILON) { - newAccelDistance = 0; - } - if ((millimeters - newAccelDistance) < EPSILON) { - newAccelDistance = millimeters; - } + //SET_SOFT_ENDSTOP_LOOSE(false); // Re-enable software endstops after tool change - accelDistance = newAccelDistance; - decelDistance = millimeters - accelDistance; - if (decelDistance < EPSILON) { - decelDistance = 0; - } - - nominal_speed = SQRT(2 * acceleration * accelDistance + sq(entry_speed)); - if (nominal_speed < leave_speed) { - nominal_speed = leave_speed; - } - - accelClocks = (nominal_speed - entry_speed) * i_acceleration; - decelClocks = (nominal_speed - leave_speed) * i_acceleration; - plateauClocks = 0; - plateau = 0; - - } - - Move move; - axisManager.axis_t0_t1.reset(); - move.start_t = 0; - move.axis_r[T0_T1_AXIS_INDEX] = L > 0.0 ? 80 : -80; - - if (accelDistance > 0) { - move.accelerate = acceleration; - move.t = accelClocks; - move.end_t = move.start_t + move.t; - move.start_pos[T0_T1_AXIS_INDEX] = axisManager.axis_t0_t1.func_manager.last_pos; - move.end_pos[T0_T1_AXIS_INDEX] = move.start_pos[T0_T1_AXIS_INDEX] + accelDistance * move.axis_r[T0_T1_AXIS_INDEX]; - axisManager.axis_t0_t1.generateLineFuncParams(&move); - } - if (plateau > 0.0) { - move.accelerate = 0; - move.start_t = move.end_t; - move.t = plateauClocks; - move.end_t = move.start_t + move.t; - move.start_pos[T0_T1_AXIS_INDEX] = move.end_pos[T0_T1_AXIS_INDEX]; - move.end_pos[T0_T1_AXIS_INDEX] = move.start_pos[T0_T1_AXIS_INDEX] + plateau * move.axis_r[T0_T1_AXIS_INDEX]; - axisManager.axis_t0_t1.generateLineFuncParams(&move); - } - if (decelDistance > 0) { - move.accelerate = -acceleration; - move.start_t = move.end_t; - move.t = decelClocks; - move.end_t = move.start_t + move.t; - move.start_pos[T0_T1_AXIS_INDEX] = move.end_pos[T0_T1_AXIS_INDEX]; - move.end_pos[T0_T1_AXIS_INDEX] = move.start_pos[T0_T1_AXIS_INDEX] + decelDistance * move.axis_r[T0_T1_AXIS_INDEX]; - axisManager.axis_t0_t1.generateLineFuncParams(&move); - } - - axisManager.T0_T1_execute_steps = 0; - axisManager.T0_T1_axis = !active_extruder; - inactive_extruder_x = axisManager.T0_T1_target_pos; - axisManager.T0_T1_last_print_time = 0; - axisManager.axis_t0_t1.is_consumed = true; - axisManager.T0_T1_simultaneously_move = true; - axisManager.T0_T1_simultaneously_move_req = false; - } - break; - - case 50: - { - switch_detect.debug_probe_poweron_sw = parser.byteval('F', 0); - } - break; - - default: - break; + SERIAL_ECHOLNPAIR("M2000 S200: T", inactive_ext, " parked at X", target_x); + SERIAL_ECHOLNPAIR("M2000 S200: Resumed with T", active_extruder, " at X", current_position.x); } - - // uint8_t z = (uint8_t)parser.byteval('Z', (uint8_t)0xFF); - // if (z != 0xFF) { - // motion_control.move_to_z((float)z, 600); - // } -} - + else { + // Original Snapmaker HMI code + if (print_control.get_mode() >= PRINT_DUPLICATION_MODE) { + LOG_I("work mode do not support this command\r\n"); + return; + } + if (axisManager.T0_T1_simultaneously_move) { + LOG_I("BUSY\r\n"); + return; + } + if (SYSTEM_STATUE_PRINTING != system_service.get_status()) { + LOG_I("Not printing, can not move T0 T1 now\r\n"); + return; + } + axisManager.T0_T1_simultaneously_move_req = true; + axisManager.T0_T1_target_pos = x_home_pos(!active_extruder); + float L = axisManager.T0_T1_target_pos - inactive_extruder_x; + float V = (float)parser.floatval('V', (float)200.0); + float A = (float)parser.floatval('A', (float)6000.0); + int32_t target_steps = (!active_extruder) == 0 ? axisManager.X0_home_step_pos : axisManager.X1_home_step_pos; + axisManager.T0_T1_calc_steps = target_steps - axisManager.inactive_x_step_pos; + int32_t float_d_to_step_d = L * planner.settings.axis_steps_per_mm[X_AXIS]; + if (abs(float_d_to_step_d - axisManager.T0_T1_calc_steps) > 5) { + axisManager.T0_T1_calc_steps = L * planner.settings.axis_steps_per_mm[X_AXIS]; + } + if (0 == axisManager.T0_T1_calc_steps){ + axisManager.T0_T1_simultaneously_move_req = false; + return; + } + float millimeters = fabs(L); + float entry_speed = 5 / 1000.0f; + float leave_speed = 5 / 1000.0f; + float nominal_speed = fabs(V) / 1000.0f; + float acceleration = fabs(A) / 1000000.0f; + float i_acceleration = 1.0f / acceleration; + float i_nominal_speed = 1.0f / nominal_speed; + float accelDistance = Planner::estimate_acceleration_distance(entry_speed, nominal_speed, acceleration); + float decelDistance = Planner::estimate_acceleration_distance(nominal_speed, leave_speed, -acceleration); + if (accelDistance < EPSILON) accelDistance = 0; + if (decelDistance < EPSILON) decelDistance = 0; + float plateau = millimeters - accelDistance - decelDistance; + float accelClocks = (nominal_speed - entry_speed) * i_acceleration; + float decelClocks = (nominal_speed - leave_speed) * i_acceleration; + float plateauClocks = plateau * i_nominal_speed; + if (plateau < 0) { + float newAccelDistance = Planner::intersection_distance(entry_speed, leave_speed, acceleration, millimeters); + if (newAccelDistance > millimeters) newAccelDistance = millimeters; + if (newAccelDistance < EPSILON) newAccelDistance = 0; + if ((millimeters - newAccelDistance) < EPSILON) newAccelDistance = millimeters; + accelDistance = newAccelDistance; + decelDistance = millimeters - accelDistance; + if (decelDistance < EPSILON) decelDistance = 0; + nominal_speed = SQRT(2 * acceleration * accelDistance + sq(entry_speed)); + if (nominal_speed < leave_speed) nominal_speed = leave_speed; + accelClocks = (nominal_speed - entry_speed) * i_acceleration; + decelClocks = (nominal_speed - leave_speed) * i_acceleration; + plateauClocks = 0; + plateau = 0; + } + Move move; + axisManager.axis_t0_t1.reset(); + move.start_t = 0; + move.axis_r[T0_T1_AXIS_INDEX] = L > 0.0 ? 80 : -80; + if (accelDistance > 0) { + move.accelerate = acceleration; + move.t = accelClocks; + move.end_t = move.start_t + move.t; + move.start_pos[T0_T1_AXIS_INDEX] = axisManager.axis_t0_t1.func_manager.last_pos; + move.end_pos[T0_T1_AXIS_INDEX] = move.start_pos[T0_T1_AXIS_INDEX] + accelDistance * move.axis_r[T0_T1_AXIS_INDEX]; + axisManager.axis_t0_t1.generateLineFuncParams(&move); + } + if (plateau > 0.0) { + move.accelerate = 0; + move.start_t = move.end_t; + move.t = plateauClocks; + move.end_t = move.start_t + move.t; + move.start_pos[T0_T1_AXIS_INDEX] = move.end_pos[T0_T1_AXIS_INDEX]; + move.end_pos[T0_T1_AXIS_INDEX] = move.start_pos[T0_T1_AXIS_INDEX] + plateau * move.axis_r[T0_T1_AXIS_INDEX]; + axisManager.axis_t0_t1.generateLineFuncParams(&move); + } + if (decelDistance > 0) { + move.accelerate = -acceleration; + move.start_t = move.end_t; + move.t = decelClocks; + move.end_t = move.start_t + move.t; + move.start_pos[T0_T1_AXIS_INDEX] = move.end_pos[T0_T1_AXIS_INDEX]; + move.end_pos[T0_T1_AXIS_INDEX] = move.start_pos[T0_T1_AXIS_INDEX] + decelDistance * move.axis_r[T0_T1_AXIS_INDEX]; + axisManager.axis_t0_t1.generateLineFuncParams(&move); + } + axisManager.T0_T1_execute_steps = 0; + axisManager.T0_T1_axis = !active_extruder; + inactive_extruder_x = axisManager.T0_T1_target_pos; + axisManager.T0_T1_last_print_time = 0; + axisManager.axis_t0_t1.is_consumed = true; + axisManager.T0_T1_simultaneously_move = true; + axisManager.T0_T1_simultaneously_move_req = false; + } + break; + case 50: + switch_detect.debug_probe_poweron_sw = parser.byteval('F', 0); + break; + default: + break; + } + } \ No newline at end of file diff --git a/snapmaker/lib/GD32F1/variants/Snapmaker_GD32F105RC/board.cpp b/snapmaker/lib/GD32F1/variants/Snapmaker_GD32F105RC/board.cpp index 9efdedd471..c9537c1ce0 100644 --- a/snapmaker/lib/GD32F1/variants/Snapmaker_GD32F105RC/board.cpp +++ b/snapmaker/lib/GD32F1/variants/Snapmaker_GD32F105RC/board.cpp @@ -217,3 +217,4 @@ __weak void __irq_otg_fs() { #ifdef __cplusplus } /* C-declarations for C++ */ #endif + diff --git a/snapmaker/module/filament_sensor.cpp b/snapmaker/module/filament_sensor.cpp index 82c8b64658..5270bbdfa3 100644 --- a/snapmaker/module/filament_sensor.cpp +++ b/snapmaker/module/filament_sensor.cpp @@ -54,12 +54,17 @@ uint16_t FilamentSensor::get_adc_val(uint8_t e) { void FilamentSensor::reset() { FILAMENT_LOOP(i) { - start_adc[i] = 0; - triggered[i] = false; - err_times[i] = 0; - check_step_count[i] = (filament_param.distance + FILAMENT_CHECK_EXTRAS_DISTANCE) * planner.settings.axis_steps_per_mm[E_AXIS_N(i)]; + reset(i); } - err_mask = ~(0xff << filament_param.check_times); + err_mask = ~(0xff << filament_param.check_times); // Revert to 8-bit mask +} + +void FilamentSensor::reset(uint8_t e) { + if (e >= FILAMENT_SENSOR_COUNT) return; + start_adc[e] = 0; + triggered[e] = false; + err_times[e] = 0; + check_step_count[e] = (filament_param.distance + FILAMENT_CHECK_EXTRAS_DISTANCE) * planner.settings.axis_steps_per_mm[E_AXIS_N(e)]; } void FilamentSensor::used_default_param() { @@ -100,23 +105,10 @@ void FilamentSensor::check() { continue; } if (start_adc[i] == 0) { - // The value is assigned once at startup next_sample(i); continue; } - // { - // static uint32_t last_log_tick_ms = 0; - // if (ELAPSED(millis(), last_log_tick_ms + 200)) { - // uint16_t adc = get_adc_val(0); - // LOG_I("E0 adc: %d\r\n", adc); - - // adc = get_adc_val(1); - // LOG_I("E1 adc: %d\r\n", adc); - // last_log_tick_ms = millis(); - // } - // } - if (e_step_count[i] > check_step_count[i]) { uint16_t adc = get_adc_val(i); int32_t diff = abs(adc - start_adc[i]); @@ -127,22 +119,6 @@ void FilamentSensor::check() { bool is_err = (diff < filament_param.threshold); - // if ((adc > dead_space) || (adc < dead_space_min)) { - // dead_space_times[i]++; - // LOG_I("extruder %d in dead_space_time "); - // if (dead_space_times[i] >= (filament_param.check_times + (SENSOR_DEAD_SPACE_DISTANCE / FILAMENT_CHECK_DISTANCE))) { - // dead_space_times[i] = 0; - // err_times[i] = err_mask; - // } - // else { - // err_times[i] = 0; - // } - // } - // else { - // dead_space_times[i] = 0; - // err_times[i] = err_times[i] << 1 | is_err; - // } - if (is_err && ((start_adc[i] > dead_space) || (start_adc[i] < dead_space_min)) && ((adc > dead_space) || (adc < dead_space_min))) { dead_space_times[i]++; @@ -150,17 +126,15 @@ void FilamentSensor::check() { LOG_I("extruder %d blocked in dead_space\r\n", i); dead_space_times[i] = 0; err_times[i] = err_mask; - } - else { + } else { err_times[i] = 0; } - } - else { + } else { if (is_err) { LOG_I("diff %d\r\n", diff); } dead_space_times[i] = 0; - err_times[i] = err_times[i] << 1 | is_err; + err_times[i] = (err_times[i] << 1) | is_err; if ((err_times[i] & err_mask) == err_mask) { LOG_I("extruder %d blocked as diff too small\r\n", i); } @@ -178,13 +152,13 @@ void FilamentSensor::check() { } void FilamentSensor::test_adc(uint8_t e, float step_mm, uint32_t count) { - uint16_t max = 0x0, min=0xffff; - uint32_t acc = 0, time=0; + uint16_t max = 0, min = 0xFFFF; + uint32_t acc = 0, time = 0; if (e >= FILAMENT_SENSOR_COUNT) { return; } uint16_t last_adc = get_adc_val(e); - SERIAL_ECHOLNPAIR("tast filament sensor ", e); + SERIAL_ECHOLNPAIR("test filament sensor: ", e); for (uint32_t i = 0; i < count; i++) { motion_control.extrude_e(step_mm, 15 * 60); planner.synchronize(); @@ -207,4 +181,4 @@ void FilamentSensor::test_adc(uint8_t e, float step_mm, uint32_t count) { acc += diff; } SERIAL_ECHOLNPAIR("max:", max, ", min:", min, ", avr:", acc / count); -} +} \ No newline at end of file diff --git a/snapmaker/module/filament_sensor.h b/snapmaker/module/filament_sensor.h index 3a108ce2f1..4995989fa2 100644 --- a/snapmaker/module/filament_sensor.h +++ b/snapmaker/module/filament_sensor.h @@ -19,83 +19,87 @@ * along with this program. If not, see . */ -#ifndef FILAMENT_SENSOR -#define FILAMENT_SENSOR - -#include "stdint.h" - -#define FILAMENT_SENSOR_COUNT 2 -#define FILAMENT_LOOP(i) for (uint8_t i = 0; i < FILAMENT_SENSOR_COUNT; i++) -#define FILAMENT_CHECK_DISTANCE 2 // mm -#define FILAMENT_CHECK_EXTRAS_DISTANCE 1 // mm -#define FILAMENT_THRESHOLD 8 // ADC diff value -#define FILAMENT_THRESHOLD_HW2 15 // ADC diff value -#define FILAMENT_CHECK_TIMES 3 -#define SENSOR_DEAD_SPACE_ADC 1433 // > 1.51V -#define SENSOR_DEAD_SPACE_ADC_HW2 4060 -#define SENSOR_DEAD_SPACE_ADC_MIN_HW2 60 -#define SENSOR_DEAD_SPACE_DISTANCE 4 // mm -typedef struct { - bool enabled[FILAMENT_SENSOR_COUNT]; - float distance; // Move this distance to detect abnormal sensing deviation - uint8_t check_times; // Determine the number of exceptions - uint16_t threshold; -}filament_check_param_t; - - -class FilamentSensor -{ - public: - void init(); - void e0_step(uint8_t step); - void e1_step(uint8_t step); - void next_sample(uint8_t e); - void enable(uint8_t e) { - filament_param.enabled[e] = true; - triggered[e] = false; - check_step_count[e] = 0; - next_sample(e); - } - void disable(uint8_t e) { - triggered[e] = false; - filament_param.enabled[e] = false; - } - void enable_all() { - FILAMENT_LOOP(i) { - enable(i); - } - } - void disable_all() { - FILAMENT_LOOP(i) { - disable(i); - } - } - bool is_trigger(uint8_t e) { - return triggered[e] && is_enable(e); - } - bool is_trigger() { - return is_trigger(0) || is_trigger(1); - } - bool is_enable(uint8_t e) { - return filament_param.enabled[e]; - } - - void check(); - void test_adc(uint8_t e, float step_mm, uint32_t count); - void reset(); - void used_default_param(); - uint16_t get_adc_val(uint8_t e); - public: - filament_check_param_t filament_param; - private: - uint8_t err_mask = 0x1; - int32_t check_step_count[FILAMENT_SENSOR_COUNT]; - uint8_t err_times[FILAMENT_SENSOR_COUNT] = {0, 0}; - int32_t e_step_count[FILAMENT_SENSOR_COUNT] = {0, 0}; - bool triggered[FILAMENT_SENSOR_COUNT] = {false, false}; - uint16_t start_adc[FILAMENT_SENSOR_COUNT] = {0, 0}; -}; - -extern FilamentSensor filament_sensor; - -#endif \ No newline at end of file + #ifndef FILAMENT_SENSOR_H + #define FILAMENT_SENSOR_H + + #include "../../Marlin/src/inc/MarlinConfig.h" // For Marlin types and NUM_RUNOUT_SENSORS + #include "stdint.h" + + #define FILAMENT_SENSOR_COUNT 2 + #define FILAMENT_LOOP(i) for (uint8_t i = 0; i < FILAMENT_SENSOR_COUNT; i++) + #define FILAMENT_CHECK_DISTANCE 2 // mm + #define FILAMENT_CHECK_EXTRAS_DISTANCE 1 // mm + #define FILAMENT_THRESHOLD 8 // ADC diff value + #define FILAMENT_THRESHOLD_HW2 15 // ADC diff value + #define FILAMENT_CHECK_TIMES 3 + #define SENSOR_DEAD_SPACE_ADC 1433 // > 1.51V + #define SENSOR_DEAD_SPACE_ADC_HW2 4060 + #define SENSOR_DEAD_SPACE_ADC_MIN_HW2 60 + #define SENSOR_DEAD_SPACE_DISTANCE 4 // mm + + typedef struct { + bool enabled[FILAMENT_SENSOR_COUNT]; + float distance; // Move this distance to detect abnormal sensing deviation + uint8_t check_times; // Determine the number of exceptions + uint16_t threshold; + } filament_check_param_t; + + class FilamentSensor + { + public: + void init(); + void e0_step(uint8_t step); + void e1_step(uint8_t step); + void next_sample(uint8_t e); + void enable(uint8_t e) { + filament_param.enabled[e] = true; + triggered[e] = false; + check_step_count[e] = 0; + next_sample(e); + } + void disable(uint8_t e) { + triggered[e] = false; + filament_param.enabled[e] = false; + } + void enable_all() { + FILAMENT_LOOP(i) { + enable(i); + } + } + void disable_all() { + FILAMENT_LOOP(i) { + disable(i); + } + } + bool is_trigger(uint8_t e) { + return triggered[e] && is_enable(e); + } + bool is_trigger() { + return is_trigger(0) || is_trigger(1); + } + bool is_enable(uint8_t e) { + return filament_param.enabled[e]; + } + + void check(); + void test_adc(uint8_t e, float step_mm, uint32_t count); + void reset(); // Resets all sensors + void reset(uint8_t e); // Resets specific sensor + void used_default_param(); + uint16_t get_adc_val(uint8_t e); + + public: + filament_check_param_t filament_param; + + private: + uint16_t err_mask = 0x1; // Changed to uint16_t for 16-bit mask + int32_t check_step_count[FILAMENT_SENSOR_COUNT]; + uint16_t err_times[FILAMENT_SENSOR_COUNT] = {0, 0}; // Changed to uint16_t + int32_t e_step_count[FILAMENT_SENSOR_COUNT] = {0, 0}; + bool triggered[FILAMENT_SENSOR_COUNT] = {false, false}; + uint16_t start_adc[FILAMENT_SENSOR_COUNT] = {0, 0}; + }; + + extern FilamentSensor filament_sensor; + + #endif // FILAMENT_SENSOR_H \ No newline at end of file diff --git a/snapmaker/module/print_control.cpp b/snapmaker/module/print_control.cpp index 47eac8f4f6..9294f253e4 100644 --- a/snapmaker/module/print_control.cpp +++ b/snapmaker/module/print_control.cpp @@ -35,6 +35,7 @@ #include "../module/filament_sensor.h" #include "exception.h" +bool is_hmi_printing = false; // Default to false (not HMI) #define PAUSE_RESUME_MOVE_FEEDRATE_MMM (9000) @@ -84,6 +85,7 @@ uint32_t PrintControl::next_req_line() { bool PrintControl::filament_check() { + if (!is_hmi_printing) return false; // Skip for OctoPrint prints bool is_trigger = false; if (dual_x_carriage_mode < DXC_DUPLICATION_MODE) { is_trigger = filament_sensor.is_trigger(active_extruder); @@ -318,6 +320,8 @@ ErrCode PrintControl::start() { system_service.return_to_idle(); return PRINT_RESULT_START_ERR_E; } + + is_hmi_printing = true; // Set for HMI-initiated prints if (homing_needed()) { motion_control.home(); @@ -591,6 +595,9 @@ ErrCode PrintControl::stop() { } // reset to normal print_control.set_noise_mode(NOISE_NOIMAL_MODE); + + // Reset HMI printing flag after print stops + is_hmi_printing = false; return E_SUCCESS; } @@ -642,4 +649,6 @@ void PrintControl::error_and_stop() { motion_control.retrack_e(PRINT_RETRACK_DISTANCE, CHANGE_FILAMENT_SPEED); motion_control.home(); system_service.set_status(SYSTEM_STATUE_IDLE); + // Reset HMI printing flag after print stops + is_hmi_printing = false; } diff --git a/snapmaker/module/print_control.h b/snapmaker/module/print_control.h index 49b6e96a4b..1b4ff54ef5 100644 --- a/snapmaker/module/print_control.h +++ b/snapmaker/module/print_control.h @@ -24,6 +24,8 @@ #include "../J1/common_type.h" #include "src/core/types.h" +extern bool is_hmi_printing; // Global flag for print source + typedef enum { PRINT_RESULT_GCODE_RECV_DONE_E = 201, PRINT_RESULT_START_ERR_E = 202, diff --git a/snapmaker/module/update.cpp b/snapmaker/module/update.cpp index bca4a21b2c..fe1a41211f 100644 --- a/snapmaker/module/update.cpp +++ b/snapmaker/module/update.cpp @@ -20,7 +20,7 @@ */ #include "update.h" -#include "../../marlin/src/core/serial.h" +#include "../../Marlin/src/core/serial.h" #include "flash_stm32.h" #include HAL_PATH(src/HAL, HAL_watchdog_STM32F1.h) diff --git a/snapmaker/scripts/platformio-targets.py b/snapmaker/scripts/platformio-targets.py index 2feaeae258..d6e90ebe2a 100644 --- a/snapmaker/scripts/platformio-targets.py +++ b/snapmaker/scripts/platformio-targets.py @@ -49,7 +49,7 @@ break if not version: - print("cannot get app version from Marlin\src\inc\Version.h") + print("cannot get app version from Marlin\\src\\inc\\Version.h") print("won't use default version: V0.0.0-2201") version = "V0.0.0" else: