diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 3d7353eadf..cfa407ea73 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -617,6 +617,11 @@ Polygon generate_rectange_polygon(const Vec2f &wt_box_min ,const Vec2f & wt_box_ return res; } +const char* flush_planner_queue_command(GCodeFlavor flavor) +{ + return flavor == gcfKlipper ? "M400\n" : "G4 S0\n"; +} + class WipeTowerWriter { public: @@ -1190,7 +1195,7 @@ public: WipeTowerWriter& flush_planner_queue() { - m_gcode += "G4 S0\n"; + m_gcode += flush_planner_queue_command(m_gcode_flavor); return *this; } diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 66e8acf1c4..a083da1fb2 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -26,6 +26,14 @@ enum GCodeFlavor : unsigned char; Polylines construct_gap_for_skip_points( const Polygon& polygon, const std::vector& skip_points, float wt_width, float gap_length, Polygon& insert_skip_polygon); +// Returns the command that makes the firmware finish its queued moves, so a command or +// custom-G-code boundary right after (resetting the extruder position, entering +// [change_filament_gcode] / [filament_start_gcode]) is not reached early. Klipper acts on +// such commands the moment it parses them, and its G4 reads only P, so the zero dwell the +// other flavors use synchronizes nothing there — M400 does. Defined in WipeTower.cpp, shared +// by WipeTower and WipeTower2. +const char* flush_planner_queue_command(GCodeFlavor flavor); + class WipeTower { public: diff --git a/src/libslic3r/GCode/WipeTower2.cpp b/src/libslic3r/GCode/WipeTower2.cpp index 51ab155dd9..5dc78d4785 100644 --- a/src/libslic3r/GCode/WipeTower2.cpp +++ b/src/libslic3r/GCode/WipeTower2.cpp @@ -386,7 +386,8 @@ public: } WipeTowerWriter2& switch_filament_monitoring(bool enable) { - m_gcode += std::string("G4 S0\n") + "M591 " + (enable ? "R" : "S0") + "\n"; + m_gcode += flush_planner_queue_command(m_gcode_flavor); + m_gcode += std::string("M591 ") + (enable ? "R" : "S0") + "\n"; return *this; } @@ -625,7 +626,7 @@ public: // Set extruder temperature, don't wait by default. WipeTowerWriter2& set_extruder_temp(int temperature, bool wait = false) { - m_gcode += "G4 S0\n"; // to flush planner queue + m_gcode += flush_planner_queue_command(m_gcode_flavor); m_gcode += "M" + std::to_string(wait ? 109 : 104) + " S" + std::to_string(temperature) + "\n"; return *this; } @@ -677,8 +678,8 @@ public: } WipeTowerWriter2& flush_planner_queue() - { - m_gcode += "G4 S0\n"; + { + m_gcode += flush_planner_queue_command(m_gcode_flavor); return *this; } diff --git a/tests/fff_print/CMakeLists.txt b/tests/fff_print/CMakeLists.txt index 70ab639faa..08f86de8a7 100644 --- a/tests/fff_print/CMakeLists.txt +++ b/tests/fff_print/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable(${_TEST_NAME}_tests test_slicing_pipeline_hook.cpp test_support_material.cpp test_trianglemesh.cpp + test_wipe_tower.cpp ) target_link_libraries(${_TEST_NAME}_tests test_common libslic3r Catch2::Catch2WithMain) set_property(TARGET ${_TEST_NAME}_tests PROPERTY FOLDER "tests") diff --git a/tests/fff_print/test_wipe_tower.cpp b/tests/fff_print/test_wipe_tower.cpp new file mode 100644 index 0000000000..de5836ba7a --- /dev/null +++ b/tests/fff_print/test_wipe_tower.cpp @@ -0,0 +1,27 @@ +#include + +#include + +#include "libslic3r/GCode/WipeTower.hpp" +#include "libslic3r/PrintConfig.hpp" + +using namespace Slic3r; + +// The wipe tower flushes the firmware's motion queue before a command or custom-G-code +// boundary that must not be reached early (an extruder-position reset, entering custom +// G-code). Klipper acts on those the moment it parses them, and its G4 reads only P, so the +// zero dwell every other flavor uses is not a flush there. +TEST_CASE("Klipper flushes the wipe tower planner queue with M400", "[WipeTower]") +{ + CHECK(std::string(flush_planner_queue_command(gcfKlipper)) == "M400\n"); +} + +TEST_CASE("Other flavors flush the wipe tower planner queue with a zero dwell", "[WipeTower]") +{ + const GCodeFlavor flavor = GENERATE(gcfMarlinLegacy, gcfRepRapFirmware, gcfRepetier, + gcfMarlinFirmware, gcfRepRapSprinter, gcfTeacup, + gcfMakerWare, gcfSailfish, gcfMach3, gcfMachinekit, + gcfSmoothie, gcfNoExtrusion); + INFO("gcode flavor enum value: " << int(flavor)); + CHECK(std::string(flush_planner_queue_command(flavor)) == "G4 S0\n"); +}