Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbubnikv <bubnikv@gmail.com>2017-11-28 17:19:57 +0300
committerbubnikv <bubnikv@gmail.com>2017-11-28 17:19:57 +0300
commit672194b475e2ec6d25ed2cc3e6164144a9f7d84e (patch)
tree666d664f135fa2d4ceb56c709d9ceb7c28e09e3f
parentf58b2173694443e3a99f0508d5164aa276b02fc4 (diff)
Ported the between_objects_gcode custom G-code blocks,
thanks @lordofhyphens, https://github.com/alexrj/Slic3r/pull/3275 Improved handling of custom G-code blocks: Slic3r will try to extract the target extruder and bed temperatures from the custom G-code blocks.
-rw-r--r--lib/Slic3r/GUI/Tab.pm9
-rw-r--r--t/custom_gcode.t11
-rw-r--r--xs/src/libslic3r/GCode.cpp121
-rw-r--r--xs/src/libslic3r/GCode.hpp3
-rw-r--r--xs/src/libslic3r/Print.cpp148
-rw-r--r--xs/src/libslic3r/PrintConfig.cpp9
-rw-r--r--xs/src/libslic3r/PrintConfig.hpp2
-rw-r--r--xs/src/slic3r/GUI/Preset.cpp4
8 files changed, 207 insertions, 100 deletions
diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm
index d479eb911..907be7872 100644
--- a/lib/Slic3r/GUI/Tab.pm
+++ b/lib/Slic3r/GUI/Tab.pm
@@ -1467,6 +1467,15 @@ sub build {
$option->height(150);
$optgroup->append_single_option_line($option);
}
+ {
+ my $optgroup = $page->new_optgroup('Between objects G-code (for sequential printing)',
+ label_width => 0,
+ );
+ my $option = $optgroup->get_option('between_objects_gcode');
+ $option->full_width(1);
+ $option->height(150);
+ $optgroup->append_single_option_line($option);
+ }
}
{
diff --git a/t/custom_gcode.t b/t/custom_gcode.t
index 2cb9a44b8..91c7e7618 100644
--- a/t/custom_gcode.t
+++ b/t/custom_gcode.t
@@ -1,4 +1,4 @@
-use Test::More tests => 40;
+use Test::More tests => 41;
use strict;
use warnings;
@@ -210,4 +210,13 @@ use Slic3r::Test;
}
}
+{
+ my $config = Slic3r::Config::new_from_defaults;
+ $config->set('complete_objects', 1);
+ $config->set('between_objects_gcode', '_MY_CUSTOM_GCODE_');
+ my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 3);
+ my $gcode = Slic3r::Test::gcode($print);
+ is scalar(() = $gcode =~ /^_MY_CUSTOM_GCODE_/gm), 2, 'between_objects_gcode is applied correctly';
+}
+
__END__
diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp
index 3c406389e..441d254f6 100644
--- a/xs/src/libslic3r/GCode.cpp
+++ b/xs/src/libslic3r/GCode.cpp
@@ -538,29 +538,23 @@ bool GCode::_do_export(Print &print, FILE *file)
// Disable fan.
if (! print.config.cooling.get_at(initial_extruder_id) || print.config.disable_fan_first_layers.get_at(initial_extruder_id))
write(file, m_writer.set_fan(0, true));
-
- // Set bed temperature if the start G-code does not contain any bed temp control G-codes.
- {
- // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
- // the custom start G-code emited these.
- //FIXME Should one parse the custom G-code to initialize the "current" bed temp state at m_writer?
- std::string gcode = m_writer.set_bed_temperature(print.config.first_layer_bed_temperature.get_at(initial_extruder_id), true);
- if (boost::ifind_first(print.config.start_gcode.value, std::string("M140")).empty() &&
- boost::ifind_first(print.config.start_gcode.value, std::string("M190")).empty())
- write(file, gcode);
- }
- // Set extruder(s) temperature before and after start G-code.
- this->_print_first_layer_extruder_temperatures(file, print, initial_extruder_id, false);
// Let the start-up script prime the 1st printing tool.
m_placeholder_parser.set("initial_tool", initial_extruder_id);
m_placeholder_parser.set("initial_extruder", initial_extruder_id);
m_placeholder_parser.set("current_extruder", initial_extruder_id);
- writeln(file, m_placeholder_parser.process(print.config.start_gcode.value, initial_extruder_id));
+ std::string start_gcode = m_placeholder_parser.process(print.config.start_gcode.value, initial_extruder_id);
+
+ // Set bed temperature if the start G-code does not contain any bed temp control G-codes.
+ this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
+ // Set extruder(s) temperature before and after start G-code.
+ this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false);
+ // Write the custom start G-code
+ writeln(file, start_gcode);
// Process filament-specific gcode in extruder order.
for (const std::string &start_gcode : print.config.start_filament_gcode.values)
writeln(file, m_placeholder_parser.process(start_gcode, (unsigned int)(&start_gcode - &print.config.start_filament_gcode.values.front())));
- this->_print_first_layer_extruder_temperatures(file, print, initial_extruder_id, true);
+ this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
// Set other general things.
write(file, this->preamble());
@@ -650,9 +644,11 @@ bool GCode::_do_export(Print &print, FILE *file)
// Ff we are printing the bottom layer of an object, and we have already finished
// another one, set first layer temperatures. This happens before the Z move
// is triggered, so machine has more time to reach such temperatures.
- write(file, m_writer.set_bed_temperature(print.config.first_layer_bed_temperature.get_at(initial_extruder_id)));
- // Set first layer extruder.
- this->_print_first_layer_extruder_temperatures(file, print, initial_extruder_id, false);
+ std::string between_objects_gcode = m_placeholder_parser.process(print.config.between_objects_gcode.value, initial_extruder_id);
+ // Set first layer bed and extruder temperatures, don't wait for it to reach the temperature.
+ this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false);
+ this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false);
+ writeln(file, between_objects_gcode);
}
// Reset the cooling buffer internal state (the current position, feed rate, accelerations).
m_cooling_buffer->reset();
@@ -774,15 +770,96 @@ bool GCode::_do_export(Print &print, FILE *file)
return true;
}
+// Parse the custom G-code, try to find mcode_set_temp_dont_wait and mcode_set_temp_and_wait inside the custom G-code.
+// Returns true if one of the temp commands are found, and try to parse the target temperature value into temp_out.
+static bool custom_gcode_sets_temperature(const std::string &gcode, const int mcode_set_temp_dont_wait, const int mcode_set_temp_and_wait, int &temp_out)
+{
+ temp_out = -1;
+ if (gcode.empty())
+ return false;
+
+ const char *ptr = gcode.data();
+ bool temp_set_by_gcode = false;
+ while (*ptr != 0) {
+ // Skip whitespaces.
+ for (; *ptr == ' ' || *ptr == '\t'; ++ ptr);
+ if (*ptr == 'M') {
+ // Line starts with 'M'. It is a machine command.
+ ++ ptr;
+ // Parse the M code value.
+ char *endptr = nullptr;
+ int mcode = int(strtol(ptr, &endptr, 10));
+ if (endptr != nullptr && endptr != ptr && (mcode == mcode_set_temp_dont_wait || mcode == mcode_set_temp_and_wait)) {
+ // M104/M109 or M140/M190 found.
+ ptr = endptr;
+ // Let the caller know that the custom G-code sets the temperature.
+ temp_set_by_gcode = true;
+ // Now try to parse the temperature value.
+ // While not at the end of the line:
+ while (strchr(";\r\n\0", *ptr) == nullptr) {
+ // Skip whitespaces.
+ for (; *ptr == ' ' || *ptr == '\t'; ++ ptr);
+ if (*ptr == 'S') {
+ // Skip whitespaces.
+ for (++ ptr; *ptr == ' ' || *ptr == '\t'; ++ ptr);
+ // Parse an int.
+ endptr = nullptr;
+ long temp_parsed = strtol(ptr, &endptr, 10);
+ if (endptr > ptr) {
+ ptr = endptr;
+ temp_out = temp_parsed;
+ }
+ } else {
+ // Skip this word.
+ for (; strchr(" \t;\r\n\0", *ptr) == nullptr; ++ ptr);
+ }
+ }
+ }
+ }
+ // Skip the rest of the line.
+ for (; *ptr != 0 && *ptr != '\r' && *ptr != '\n'; ++ ptr);
+ // Skip the end of line indicators.
+ for (; *ptr == '\r' || *ptr == '\n'; ++ ptr);
+ }
+ return temp_set_by_gcode;
+}
+
+// Write 1st layer bed temperatures into the G-code.
+// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
+// M140 - Set Extruder Temperature
+// M190 - Set Extruder Temperature and Wait
+void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
+{
+ // Initial bed temperature based on the first extruder.
+ int temp = print.config.first_layer_bed_temperature.get_at(first_printing_extruder_id);
+ // Is the bed temperature set by the provided custom G-code?
+ int temp_by_gcode = -1;
+ bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, temp_by_gcode);
+ if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
+ temp = temp_by_gcode;
+ // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if
+ // the custom start G-code emited these.
+ std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait);
+ if (! temp_by_gcode)
+ write(file, set_temp_gcode);
+}
+
// Write 1st layer extruder temperatures into the G-code.
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
-// FIXME this does not work correctly for multi-extruder, single heater configuration as it emits multiple preheat commands for the same heater.
// M104 - Set Extruder Temperature
// M109 - Set Extruder Temperature and Wait
-void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, unsigned int first_printing_extruder_id, bool wait)
+void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait)
{
- if (boost::ifind_first(print.config.start_gcode.value, std::string("M104")).empty() &&
- boost::ifind_first(print.config.start_gcode.value, std::string("M109")).empty()) {
+ // Is the bed temperature set by the provided custom G-code?
+ int temp_by_gcode = -1;
+ if (custom_gcode_sets_temperature(gcode, 104, 109, temp_by_gcode)) {
+ // Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
+ int temp = print.config.first_layer_temperature.get_at(first_printing_extruder_id);
+ if (temp_by_gcode >= 0 && temp_by_gcode < 1000)
+ temp = temp_by_gcode;
+ m_writer.set_temperature(temp_by_gcode, wait, first_printing_extruder_id);
+ } else {
+ // Custom G-code does not set the extruder temperature. Do it now.
if (print.config.single_extruder_multi_material.value) {
// Set temperature of the first printing extruder only.
int temp = print.config.first_layer_temperature.get_at(first_printing_extruder_id);
diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp
index e68cf49c7..aa90ac968 100644
--- a/xs/src/libslic3r/GCode.hpp
+++ b/xs/src/libslic3r/GCode.hpp
@@ -268,7 +268,8 @@ protected:
std::pair<const PrintObject*, Point> m_last_obj_copy;
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
- void _print_first_layer_extruder_temperatures(FILE *file, Print &print, unsigned int first_printing_extruder_id, bool wait);
+ void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
+ void _print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
// this flag triggers first layer speeds
bool on_first_layer() const { return m_layer != nullptr && m_layer->id() == 0; }
diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp
index 4ad08192a..78ebf9294 100644
--- a/xs/src/libslic3r/Print.cpp
+++ b/xs/src/libslic3r/Print.cpp
@@ -81,80 +81,80 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
// Cache the plenty of parameters, which influence the G-code generator only,
// or they are only notes not influencing the generated G-code.
- static std::unordered_set<std::string> steps_ignore;
- if (steps_ignore.empty()) {
- steps_ignore.insert("avoid_crossing_perimeters");
- steps_ignore.insert("bed_shape");
- steps_ignore.insert("bed_temperature");
- steps_ignore.insert("before_layer_gcode");
- steps_ignore.insert("bridge_acceleration");
- steps_ignore.insert("bridge_fan_speed");
- steps_ignore.insert("cooling");
- steps_ignore.insert("default_acceleration");
- steps_ignore.insert("deretract_speed");
- steps_ignore.insert("disable_fan_first_layers");
- steps_ignore.insert("duplicate_distance");
- steps_ignore.insert("end_gcode");
- steps_ignore.insert("end_filament_gcode");
- steps_ignore.insert("extrusion_axis");
- steps_ignore.insert("extruder_clearance_height");
- steps_ignore.insert("extruder_clearance_radius");
- steps_ignore.insert("extruder_colour");
- steps_ignore.insert("extruder_offset");
- steps_ignore.insert("extrusion_multiplier");
- steps_ignore.insert("fan_always_on");
- steps_ignore.insert("fan_below_layer_time");
- steps_ignore.insert("filament_colour");
- steps_ignore.insert("filament_diameter");
- steps_ignore.insert("filament_density");
- steps_ignore.insert("filament_notes");
- steps_ignore.insert("filament_cost");
- steps_ignore.insert("filament_max_volumetric_speed");
- steps_ignore.insert("first_layer_acceleration");
- steps_ignore.insert("first_layer_bed_temperature");
- steps_ignore.insert("first_layer_speed");
- steps_ignore.insert("gcode_comments");
- steps_ignore.insert("gcode_flavor");
- steps_ignore.insert("infill_acceleration");
- steps_ignore.insert("infill_first");
- steps_ignore.insert("layer_gcode");
- steps_ignore.insert("min_fan_speed");
- steps_ignore.insert("max_fan_speed");
- steps_ignore.insert("min_print_speed");
- steps_ignore.insert("max_print_speed");
- steps_ignore.insert("max_volumetric_speed");
- steps_ignore.insert("max_volumetric_extrusion_rate_slope_positive");
- steps_ignore.insert("max_volumetric_extrusion_rate_slope_negative");
- steps_ignore.insert("notes");
- steps_ignore.insert("only_retract_when_crossing_perimeters");
- steps_ignore.insert("output_filename_format");
- steps_ignore.insert("perimeter_acceleration");
- steps_ignore.insert("post_process");
- steps_ignore.insert("printer_notes");
- steps_ignore.insert("retract_before_travel");
- steps_ignore.insert("retract_before_wipe");
- steps_ignore.insert("retract_layer_change");
- steps_ignore.insert("retract_length");
- steps_ignore.insert("retract_length_toolchange");
- steps_ignore.insert("retract_lift");
- steps_ignore.insert("retract_lift_above");
- steps_ignore.insert("retract_lift_below");
- steps_ignore.insert("retract_restart_extra");
- steps_ignore.insert("retract_restart_extra_toolchange");
- steps_ignore.insert("retract_speed");
- steps_ignore.insert("slowdown_below_layer_time");
- steps_ignore.insert("standby_temperature_delta");
- steps_ignore.insert("start_gcode");
- steps_ignore.insert("start_filament_gcode");
- steps_ignore.insert("toolchange_gcode");
- steps_ignore.insert("threads");
- steps_ignore.insert("travel_speed");
- steps_ignore.insert("use_firmware_retraction");
- steps_ignore.insert("use_relative_e_distances");
- steps_ignore.insert("use_volumetric_e");
- steps_ignore.insert("variable_layer_height");
- steps_ignore.insert("wipe");
- }
+ static std::unordered_set<std::string> steps_ignore = {
+ "avoid_crossing_perimeters",
+ "bed_shape",
+ "bed_temperature",
+ "before_layer_gcode",
+ "between_objects_gcode",
+ "bridge_acceleration",
+ "bridge_fan_speed",
+ "cooling",
+ "default_acceleration",
+ "deretract_speed",
+ "disable_fan_first_layers",
+ "duplicate_distance",
+ "end_gcode",
+ "end_filament_gcode",
+ "extrusion_axis",
+ "extruder_clearance_height",
+ "extruder_clearance_radius",
+ "extruder_colour",
+ "extruder_offset",
+ "extrusion_multiplier",
+ "fan_always_on",
+ "fan_below_layer_time",
+ "filament_colour",
+ "filament_diameter",
+ "filament_density",
+ "filament_notes",
+ "filament_cost",
+ "filament_max_volumetric_speed",
+ "first_layer_acceleration",
+ "first_layer_bed_temperature",
+ "first_layer_speed",
+ "gcode_comments",
+ "gcode_flavor",
+ "infill_acceleration",
+ "infill_first",
+ "layer_gcode",
+ "min_fan_speed",
+ "max_fan_speed",
+ "min_print_speed",
+ "max_print_speed",
+ "max_volumetric_speed",
+ "max_volumetric_extrusion_rate_slope_positive",
+ "max_volumetric_extrusion_rate_slope_negative",
+ "notes",
+ "only_retract_when_crossing_perimeters",
+ "output_filename_format",
+ "perimeter_acceleration",
+ "post_process",
+ "printer_notes",
+ "retract_before_travel",
+ "retract_before_wipe",
+ "retract_layer_change",
+ "retract_length",
+ "retract_length_toolchange",
+ "retract_lift",
+ "retract_lift_above",
+ "retract_lift_below",
+ "retract_restart_extra",
+ "retract_restart_extra_toolchange",
+ "retract_speed",
+ "slowdown_below_layer_time",
+ "standby_temperature_delta",
+ "start_gcode",
+ "start_filament_gcode",
+ "toolchange_gcode",
+ "threads",
+ "travel_speed",
+ "use_firmware_retraction",
+ "use_relative_e_distances",
+ "use_volumetric_e",
+ "variable_layer_height",
+ "wipe"
+ };
std::vector<PrintStep> steps;
std::vector<PrintObjectStep> osteps;
diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp
index 54d51c237..217f9bdef 100644
--- a/xs/src/libslic3r/PrintConfig.cpp
+++ b/xs/src/libslic3r/PrintConfig.cpp
@@ -48,6 +48,15 @@ PrintConfigDef::PrintConfigDef()
def->height = 50;
def->default_value = new ConfigOptionString("");
+ def = this->add("between_objects_gcode", coString);
+ def->label = "Between objects G-code";
+ def->tooltip = "This code is inserted between objects when using sequential printing. By default extruder and bed temperature are reset using non-wait command; however if M104, M109, M140 or M190 are detected in this custom code, Slic3r will not add temperature commands. Note that you can use placeholder variables for all Slic3r settings, so you can put a \"M109 S[first_layer_temperature]\" command wherever you want.";
+ def->cli = "between-objects-gcode=s";
+ def->multiline = true;
+ def->full_width = true;
+ def->height = 120;
+ def->default_value = new ConfigOptionString("");
+
def = this->add("bottom_solid_layers", coInt);
def->label = "Bottom";
def->category = "Layers and Perimeters";
diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp
index 20f787b1e..ab58aa356 100644
--- a/xs/src/libslic3r/PrintConfig.hpp
+++ b/xs/src/libslic3r/PrintConfig.hpp
@@ -452,6 +452,7 @@ class GCodeConfig : public StaticPrintConfig
STATIC_PRINT_CONFIG_CACHE(GCodeConfig)
public:
ConfigOptionString before_layer_gcode;
+ ConfigOptionString between_objects_gcode;
ConfigOptionFloats deretract_speed;
ConfigOptionString end_gcode;
ConfigOptionStrings end_filament_gcode;
@@ -500,6 +501,7 @@ protected:
void initialize(StaticCacheBase &cache, const char *base_ptr)
{
OPT_PTR(before_layer_gcode);
+ OPT_PTR(between_objects_gcode);
OPT_PTR(deretract_speed);
OPT_PTR(end_gcode);
OPT_PTR(end_filament_gcode);
diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp
index 214c111a4..e4b0448cf 100644
--- a/xs/src/slic3r/GUI/Preset.cpp
+++ b/xs/src/slic3r/GUI/Preset.cpp
@@ -204,8 +204,8 @@ const std::vector<std::string>& Preset::printer_options()
s_opts = {
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
"octoprint_host", "octoprint_apikey", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
- "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
- "printer_notes"
+ "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
+ "between_objects_gcode", "printer_notes"
};
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
}